'08.05.22 以前の記事より良さそうな方法が見つかったので記事を書き変えました。

'08.11.08 この記事の方法だと問題があるようです。コメントを読んでいただければと思います。



ファイルのサイズ(バイト数)を取得してみようと思います。

VC++とか使用していれば、ファイルの情報を取得する関数がありそうですが、C言語標準では無かった気がします。(涙)



【サンプル】

#include <cstdlib>
#include <iostream>
#include <fstream>
#include <sstream>


using namespace std;


int main(int argc, char *argv[])
{
//ファイル名をフルパスで指定しましょう
ifstream ifs("D:\\test.txt", ios_base::binary);


//VC++の場合、peek()で読み込まないとファイルが開かれないっぽい
//ifs.peek();
//streamsize size = ifs.rdbuf()->in_avail();

//上記の方法は問題ありそうなのでコメントアウトしました。
streamsize size = ifs.seekg(0, ios::end).tellg();
ifs.seekg(0, ios::beg);

//ファイルサイズを出力します
cout << "size=" << size << endl;


system("PAUSE");
return EXIT_SUCCESS;
}



【出力】

18



【説明】

この方法では、ファイルストリーム内のストリームバッファの関数を使用しています。


まず、rdbuf()関数について。

これは、ストリームバッファクラスを取得する関数です。


以下は、in_avail()をコメントアウトしたことで、説明の意味がなくなったため取り消しました。

次に、そのバッファクラスのin_avail()関数です。

これは、現在の位置からEOFまでのバイト数を返します。

つまり、in_avail()はファイルのサイズを取得する関数ではありません。

でも、現在指している位置が先頭であれば、当然ファイルの読み込みサイズになります!

プログラム上で行っている内容は至極単純です。
まず、ファイルの一番最後までファイルポインタを進めます。
その状態で、ポインタの位置を知るためにtellg()を呼び出します。
ファイルポインタは0から始まるので、その位置がファイルのサイズとなります。

最後に、ポインタがファイルの最後尾にいるので、seekg()でファイルの先頭にします。
seekg()内のios::begは、ファイルの先頭を表す定数です。

そし~て、ぼく~は、途方にくれない!

ということです(すみません。。)



以下は、in_avail()をコメントアウトしたことで、説明の意味がなくなったため取消ました。

【補足】

サイズを計算する前に、ifs.peek()しています。

この関数は、現在指している位置を移動せずに1バイトを取得する関数です。

取得した値は変数に入れていないので、全く意味の無いはずの関数です。

どうしてこんなことしてるのでしょうか?


実は、VC++対策です。

VC++は何故かコンストラクタでクラスを作成しただけでは内部の状態を初期化してくれないようなのです。

(実験した感じで状況証拠しかありませんが)

そのままin_avail()しても、0 が返って来ます。

でもpeek()を呼び出すと、1バイト読み出すために初期化してちゃんとサイズを返してくれるようです。



【注意】

ここでは、ファイルサイズを取得するには?と言うタイトルにしたので、

ファイルサイズを取得するように、バイナリモード( ios_base::binary)でファイルを開きました。

もし、ifstream ifs("D:\\test.txt")で開くとテキストモードで開きます。


こうすると、改行コードが2バイト(\r\n)のものも環境によっては1バイト(\n)になったりします。

なので、32バイトのファイルのうち改行が1つあれば上記の結果は31バイトになります。

in_avail()は、読み込みのサイズを取得するので、モードによって取得できるサイズが違うので

目的によってどちらのモードで開くかを決めましょう!



参考:

ファイルの内容を効率よくstringに入れるには?

バイナリモード、テキストモードとは?(ファイルのオープンモード)