ifstreamでバイナリファイルを読み込んだ時の挙動で気になる事が…
通常、バイナリファイルを全て読み込む時には
ifstream ifs
ifs.open( ファイル名, ios::in | ios::binary );
if ( ifs ) {
while( !ifs.eof() ) {
ifs.read( (char*)変数, sizeof(変数) );
}
}
ってな感じで変数に逐次読み込んで行くのだけど、これだと何故かバイナリファイル中のサイズ+1のreadがされてしまうみたい。なぜかeof()がtrueになるのは、ファイルの全データを読み込んだ後のread関数を呼んだ後のような…。
取り合えず以下のようにすると、その問題を回避できるみたい。
ifstream ifs
ifs.open( ファイル名, ios::in | ios::binary );
if ( ifs ) {
while( true ) {
ifs.read( (char*)変数, sizeof(変数) );
if ( ifs.eof() ) break;
}
}
readを呼んだ後にeofをチェックしてあげると。
でも、この場合空ファイル(サイズ0バイトのファイル)を開くと必ず1ワードの無効値が取得できてしまう。それを避けるうまい方法がイマイチ思いつかない…[E:bearing]
なんでこうなるか?という原因やけど、おそらくifstreamクラスの中でのeofチェックは実際にデータ取得をする時に判定されているのではないかと推測される。つまり、ifs.eof()はファイルの終端まで読み終わったかどうかを知る関数であって、ストリームポインタがファイル終端にある事を知る関数ではないのではないかと。その証拠に、最初のコードで0バイトのファイルを開くとwhileの条件文が真となってループの中が1度だけ実行される。
こうなると、やっぱりストリームイテレータを使ってファイルから読み込むのが良いのやろうけど、そっちはそっちで文字列読み込み -> 数値変換って挙動をするようで…。>>演算子をオーバーロードするという手もあるのだけど、他にも影響でそうやしなぁ。(ビットシフトする箇所あるし…あ、でもfstreamに対してビットシフトはしないから問題ないのか?)
今日は、この挙動に違和感を感じた一日でしたなぁ。
(2009/12/12追記)
一応の解決をみましたので、解決法にリンク貼っておきます。
[C++] fstream eof()とread()の挙動
こちらのページ(日々此精進: 【C++】ifstreamのeofメンバ関数(違和感がある挙動))と全く同じ挙動を確認。VCでもgccでも確認したので、これはSTLの仕様ぽい。 いままで全然気がつかなかったんですが、10000個しかデータが入ってないハズが何故か10001個読み込んでいたこ…
私もこのeof()の仕様はおかしいと思います。
tuedaさん、
コメントありがとうございます。
実用性という事から考えたら、確かにこのeofの仕様は使いにくいです。
ただしSTLがテンプレートで実装されており、速度面でもペナルティを少なくするという方針である事を考えると有りかもしれません。
一応、
http://murakan.cocolog-nifty.com/blog/2009/12/cstreameof-7401.html
こちらで私なりの答えとしておりますのでご参考まで。
まぁ直感的でない事は確かなのですが。