【C/C++】ifstreamのeofメンバ関数(違和感がある挙動)

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/C++】 streamクラスのeofメンバ

Author: kan
初めてプログラムらしきものを作ったのは幼稚園の時。それから約40年経ち、現在はデジタル回路設計から信号処理、機械学習まで幅広い経験を活かしてシステムアーキテクトとして活動中。超並列処理、デジタル回路とソフトウェアのバランス設計が得意分野。 Linux/Mac/Windows使い。 C/C++を主要言語として、Unity、Qtなどのフレームワーク興味あり。UI/UXデザイン、STL拡張など。 音声処理、画像処理、技術コンサルは仕事でも請け負います。 一般ソフトウェア開発プロセス、医療機器ソフトウェア開発プロセス作成も進行中。

3 thoughts on “【C/C++】ifstreamのeofメンバ関数(違和感がある挙動)

  1. [C++] fstream eof()とread()の挙動

    こちらのページ(日々此精進: 【C++】ifstreamのeofメンバ関数(違和感がある挙動))と全く同じ挙動を確認。VCでもgccでも確認したので、これはSTLの仕様ぽい。 いままで全然気がつかなかったんですが、10000個しかデータが入ってないハズが何故か10001個読み込んでいたこ…

  2. tuedaさん、
    コメントありがとうございます。
    実用性という事から考えたら、確かにこのeofの仕様は使いにくいです。
    ただしSTLがテンプレートで実装されており、速度面でもペナルティを少なくするという方針である事を考えると有りかもしれません。
    一応、
    http://murakan.cocolog-nifty.com/blog/2009/12/cstreameof-7401.html
    こちらで私なりの答えとしておりますのでご参考まで。
    まぁ直感的でない事は確かなのですが。

kan へ返信する コメントをキャンセル

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください