#はじめに
C++でファイルの存在を確かめる方法はいくつかあるようだが,ファイルの有無に関わらず結局ファイルストリームで情報を追加していくので,そのファイルストリームだけでファイルの存在を確認できないかと試した.
自分の場合は数値ログをcsvで残そうと思ったのだが,無骨に数値だけとするよりも一行目にタイトル行があった方が後工程で処理が楽になるという目的のためにファイルの存在を調べたいと考えた.
拡張子はtxtとしたが,書き換え可能なファイルならバイナリファイルだろうと基本的に同じ動作をするのではないかと思う.
#ファイルストリーム
c++標準のファイルストリームと一口に言っても入力,出力,入出力で一応クラスが違う.普段は面倒なので入出力のクラスでまとめる事が多いが,今回はクラスの違いによってopenメソッドの挙動の違いを利用しているので,少し違いを意識する必要がある.
#メソッド
(初心者向け:メソッドはクラスに使う関数みたいなものです)
クラスが違うとはいえメソッドの表現は共通しているので,今回は一覧で取得する.
今回使うメソッドは次のとおり.
bool(ファイルストリームオブジェクト)
is_open
fail
good
bad
eof
#検証
実行環境はVisualStudio2013,新しいプロジェクトでソースを作成し,記事末尾のコードを入れて実行するだけ.
一度実行するとファイルが生成されたままになるので,再び動作させるときは対象ディレクトリからテキストファイルを削除しておく.
#結果
(見やすさのために出力の順序を調整しています)
ファイルを開く前(対象ファイル名も不定)
if_s | of_s | f_s | |
---|---|---|---|
bool | 1 | 1 | 1 |
is_open | 0 | 0 | 0 |
fail | 0 | 0 | 0 |
good | 1 | 1 | 1 |
bad | 0 | 0 | 0 |
eof | 0 | 0 | 0 |
ファイルを開こうとした後(対象ファイルは存在しない)
if_s | of_s | f_s | |
---|---|---|---|
bool | 0 | 1 | 0 |
is_open | 0 | 1 | 0 |
fail | 1 | 0 | 1 |
good | 0 | 1 | 0 |
bad | 0 | 0 | 0 |
eof | 0 | 0 | 0 |
ファイルを開こうとし,ファイルが存在し,内容がないとき
if_s | of_s | f_s | |
---|---|---|---|
bool | 1 | 1 | 1 |
is_open | 1 | 1 | 1 |
fail | 0 | 0 | 0 |
good | 1 | 1 | 1 |
bad | 0 | 0 | 0 |
eof | 0 | 0 | 0 |
ファイルを開こうとし,ファイルが存在し,内容があるとき
if_s | of_s | f_s | |
---|---|---|---|
bool | 1 | 1 | 1 |
is_open | 1 | 1 | 1 |
fail | 0 | 0 | 0 |
good | 1 | 1 | 1 |
bad | 0 | 0 | 0 |
eof | 0 | 0 | 0 |
#考察
ofstreamはファイルの有無に関わらずファイルを作ってしまうため,open処理の時点でファイルを開く事に成功してしまう.
ifstreamとfstreamはファイルがない場合は(都合のいいことに)ファイルを開く事に失敗してくれるのでプロパティを呼び出す事でファイルの有無を判別する事ができることになる.
ただし,fstreamについてはデフォルトのmodeがin|outになっていることに注意すべきで,これをただ単にoutとするとofstreamと同様の処理になりファイルの有無が判別できなくなる.
また,modeがin|outの場合,存在しないファイルにそのまま書き込む事ができないのでmodeをoutに指定しなおしてファイルを開きなおす必要がある.
処理を明確にするためにifstreamを使ってファイルの有無だけを調べて状態を変数に格納してすぐ閉じるのもいいかもしれない.
#ファイルの有無に応じて処理を分岐させる
今回は一つのfstreamオブジェクトでコードを書いた.
modeを変えて開きなおしてるけど,もしかしたらもう少しうまく書けるかもしれない.
このコードではファイルがない場合,ヘッダーデータを追加し,データを入力する.
ファイルがある場合,末尾にデータを追加する.
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
void main(){
fstream f_File;
f_File.open("f_File.txt", ios_base::in);
if (f_File.fail()) {
f_File.open("f_File.txt", ios_base::out);
f_File << "Header data\n";
}
else{
f_File.close();
f_File.open("f_File.txt", ios_base::app);
}
f_File << "value data\n";
f_File.close();
}
#おわりに
今回の記事は探してたらこのブログ
ifstream でテキストファイルを読み込む場合のあれこれ
が見つかったので検証範囲を広げる目的で書きました.
本文中に間違いなどありましたらコメントをいただけると助かります.
#検証したソースコード
本文中で挙動を検証したコード.
コピペで動作すると思います.
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
void main(){
ifstream if_File;
ofstream of_File;
fstream f_File;
cout
<< "\t" << "if_s\tof_s\tf_s\n";
//######//
// ファイルを開く前(対象ファイル名も不定)
cout
<< "not open files yet.\n"
<< "bool\t" << bool(if_File) << "\t" << bool(of_File) << "\t" << bool(f_File) << "\n"
<< "is_open\t" << if_File.is_open() << "\t" << of_File.is_open() << "\t" << f_File.is_open() << "\n"
<< "fail\t" << if_File.fail() << "\t" << of_File.fail() << "\t" << f_File.fail() << "\n"
<< "good\t" << if_File.good() << "\t" << of_File.good() << "\t" << f_File.good() << "\n"
<< "bad\t" << if_File.bad() << "\t" << of_File.bad() << "\t" << f_File.bad() << "\n"
<< "eof\t" << if_File.eof() << "\t" << of_File.eof() << "\t" << f_File.eof() << "\n"
<< endl;
//######//
if_File.open("if_File.txt");
of_File.open("of_File.txt");
f_File.open("f_File.txt");
// ファイルを開こうとした後(対象ファイルは存在しない)
cout
<< "tried to open files (files does not exist).\n"
<< "bool\t" << bool(if_File) << "\t" << bool(of_File) << "\t" << bool(f_File) << "\n"
<< "is_open\t" << if_File.is_open() << "\t" << of_File.is_open() << "\t" << f_File.is_open() << "\n"
<< "fail\t" << if_File.fail() << "\t" << of_File.fail() << "\t" << f_File.fail() << "\n"
<< "good\t" << if_File.good() << "\t" << of_File.good() << "\t" << f_File.good() << "\n"
<< "bad\t" << if_File.bad() << "\t" << of_File.bad() << "\t" << f_File.bad() << "\n"
<< "eof\t" << if_File.eof() << "\t" << of_File.eof() << "\t" << f_File.eof() << "\n"
<< endl;
if_File.close();
of_File.close();
f_File.close();
//######//
of_File.open("if_File.txt"), of_File.close();
of_File.open("of_File.txt"), of_File.close();
of_File.open("f_File.txt"), of_File.close();
if_File.open("if_File.txt");
of_File.open("of_File.txt");
f_File.open("f_File.txt");
// ファイルを開こうとし,ファイルが存在し,内容がないとき
cout
<< "tried to open files (files exist but blank).\n"
<< "bool\t" << bool(if_File) << "\t" << bool(of_File) << "\t" << bool(f_File) << "\n"
<< "is_open\t" << if_File.is_open() << "\t" << of_File.is_open() << "\t" << f_File.is_open() << "\n"
<< "fail\t" << if_File.fail() << "\t" << of_File.fail() << "\t" << f_File.fail() << "\n"
<< "good\t" << if_File.good() << "\t" << of_File.good() << "\t" << f_File.good() << "\n"
<< "bad\t" << if_File.bad() << "\t" << of_File.bad() << "\t" << f_File.bad() << "\n"
<< "eof\t" << if_File.eof() << "\t" << of_File.eof() << "\t" << f_File.eof() << "\n"
<< endl;
if_File.close();
of_File.close();
f_File.close();
//######//
of_File.open("if_File.txt"), of_File << "test" << endl, of_File.close();
of_File.open("of_File.txt"), of_File << "test" << endl, of_File.close();
of_File.open("f_File.txt"), of_File << "test" << endl, of_File.close();
if_File.open("if_File.txt");
of_File.open("of_File.txt", ios_base::app); // 追記モードにする
f_File.open("f_File.txt");
// ファイルを開こうとし,ファイルが存在し,内容があるとき
cout
<< "tried to open files (files exist with any data).\n"
<< "bool\t" << bool(if_File) << "\t" << bool(of_File) << "\t" << bool(f_File) << "\n"
<< "is_open\t" << if_File.is_open() << "\t" << of_File.is_open() << "\t" << f_File.is_open() << "\n"
<< "fail\t" << if_File.fail() << "\t" << of_File.fail() << "\t" << f_File.fail() << "\n"
<< "good\t" << if_File.good() << "\t" << of_File.good() << "\t" << f_File.good() << "\n"
<< "bad\t" << if_File.bad() << "\t" << of_File.bad() << "\t" << f_File.bad() << "\n"
<< "eof\t" << if_File.eof() << "\t" << of_File.eof() << "\t" << f_File.eof() << "\n"
<< endl;
if_File.close();
of_File.close();
f_File.close();
int a;
cin >> a;
}