9
9

More than 3 years have passed since last update.

[C++] ifstreamでファイルを読む際のファイル存在チェック

Posted at

C++においてファイルの中身を読み込む際にはifstreamを使う。この時にファイルが存在しなかったり不正なファイルを入力したりした時の挙動については少し注意する必要がある。

ifstreamの挙動

正常な場合

例えば、以下のような入力ファイルがあったとして

input.txt
1 2

それを変数に読み込む場合、以下のようなコードを書く。

int i, j;
std::ifstream fin("input.txt");
fin >> i >> j;
std::cout << "(i,j) = (" << i << "," << j << ")" << std::endl;  // => (1,2)

入力ファイルが存在し、適切なフォーマットで書かれているならば何も問題は起きない。

ファイルが存在しない場合

しかし、もし入力ファイルが存在しなかったらどうなるか?

    int i, j;
    std::ifstream fin("do_not_exist");
    fin >> i >> j;
    std::cout << "(i,j) = (" << i << "," << j << ")" << std::endl;   // => (0,0) (挙動は未定義?)

実はその場合にも実行時例外などは送出されず、プログラムが正常終了してしまう。

ファイルフォーマットが不正な場合

さらに、以下のような不正なフォーマットの場合を考えよう。

invalid.txt
1 a

このファイルに対して上記のコードを動かしても実行時例外などは何も発生せず、(1,0)と表示される。
(ただし、jの値がどうなるかは未定義かも。私の環境ではこうなったというだけかもしれない。)

チェック方法

このような不正なフォーマットのファイルが入ってきた場合のエラーをどのように検出するべきか?
ifstreamの状態をチェックするには fin.good(), fin.is_open() など様々なメソッドがありややこしいが、結論から言えばoperator boolでチェックするのがベストプラクティスになる。
要するに

std::ifstream fin("....txt");
if( !fin ) {
   .... // 何かエラーが起きている
}

ファイルの存在やパーミッションについてはfin.is_open()でチェックすることができるが、operator boolis_openによるチェックも含んでいる。
https://stackoverflow.com/questions/24097580/ifstreamis-open-vs-ifstreamfail
https://en.cppreference.com/w/cpp/io/basic_ios/operator_bool

例えば、先ほどの例での結果は以下のようになる。

// 正常系の場合
    int i, j;
    std::ifstream fin("input.txt");
    std::cout << static_cast<bool>(fin) << std::endl;    // => 1
    fin >> i >> j;
    std::cout << "(i,j) = (" << i << "," << j << ")" << std::endl;   // (1,2)
    std::cout << static_cast<bool>(fin) << std::endl;    // => 1

// ファイルが存在しない場合
    int i, j;
    std::ifstream fin("do_not_exist");
    std::cout << static_cast<bool>(fin) << std::endl;     // => 0
    fin >> i >> j;
    std::cout << "(i,j) = (" << i << "," << j << ")" << std::endl;
    std::cout << static_cast<bool>(fin) << std::endl;     // => 0

// 入力の形式が不正な場合
    int i, j;
    std::ifstream fin("invalid.txt");
    std::cout << static_cast<bool>(fin) << std::endl;     // => 1
    fin >> i >> j;
    std::cout << "(i,j) = (" << i << "," << j << ")" << std::endl;

    std::cout << static_cast<bool>(fin) << std::endl;     // => 0

というわけで、入力ファイルが存在するかどうかをチェックするためにもifstreamでファイルを開いたら最低限次のようなチェックを入れておくことを習慣化しておくとよい。

ifstream fin("my_file.txt");
if (!fin) {
   // エラー処理
}
9
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
9