■ C++のファイル入出力 ■ ■ 初めに
此処では、Visual Studio 2017 を起動し、新しいプロジェクトで、Visual C++の Windows デスクトッ プを選択し、Windows コンソールアプリケーションを作成する。
■ 使用クラス
C++の場合、ファイルの入出力に使用するクラスは、ifstream、ofstream、fstream の 3 種類が有り、 頭に i(input)が付いた ifstream が入力、o(output)が付いた ofstream が出力、何も付かない fstream が両用を表す。 クラス名 入出力別 派生元クラス ifstream 入力 istream ofstream 出力 ostream fstream 両用 iostream 孰れも fstream をインクルードする事で使える様に成る。 #include <fstream>
フ
ファ
ァイ
イル
ルの
の入
入出
出力
力
■ オープンモード オープンモードは、列挙型 open_mode の各ビットの論理和(OR)を取って設定する。open_mode は、 ios クラスの公開部で下記の様に定義されて居る。 入出力別 モード 値 解説 両用 ios::binary 0 ファイルをバイナリモードで開く ios::in 1 読み込み専用で開く 入力 ios::ate 4 開く時に EOF 迄移動する ios::out 2 出力用にファイルを開く ios::app 8 追加(アペンド)出力 出力 ios::trunc 16 既存のファイルを上書きする 入出力両用でファイルをオープンする時は、ios::in と ios::out の和をモードに指定する。 fstream inoutFile("ファイル名", ios::in|ios::out);
■ ファイルのオープンとクローズ
下記の様に、コンストラクタにファイル名を指定した場合、ファイルストリームのインスタンスが生成 されると同時に、ファイルがオープンされる。
std::ifstream fromFile("sample.txt");
if (!fromFile) std::cout << "Unable to open for input mode !¥n"; else std::cout << "Successfully open for input mode !¥n"; fromFile.close();
std::ofstream toFile("thatFile");
if (!toFile) std::cout << "Unable to open for output mode !¥n"; else std::cout << "Successfully open for output mode !¥n"; toFile.close();
std::fstream inoutFile("sample.txt", std::ios::in | std::ios::out); if (!inoutFile) std::cout << "Unable to open for in/out mode !¥n"; else std::cout << "Successfully open in/out mode !¥n";
inoutFile.close(); 亦、下記の様に、ファイルを指定せずにファイルストリームの宣言丈を行い、後にファイルを明示的に オープンする事も出来る。 std::ifstream fromFile; fromFile.open("sample.txt", std::ios::in); fromFile.close(); std::ofstream toFile; toFile.open("sample.txt", std::ios::out); toFile.close(); std::ofstream inoutFile; inoutFile.open("sample.txt", std::ios::out|std::ios::out); inoutFile.close(); コンストラクタにファイル名を指定してオープンしたり、open 関数を使用してオープンしたファイル は、ファイルストリームが破棄された時点(delete するか、スコープ外に出る時点)で自動的にクロー ズされるが、オープンしたファイルは、必ず close でクローズする物だと憶えて欲しい。
■ 入力 ファイルからデータを読み込む時、下記のモードでファイルをオープンする(ios::in と ios::ate はシー ケンシャルファイル、ios::binary はバイナリファイルに使用する)。 モード 解説 ios::in 読み込み専用で開く ios::ate 開く時に EOF 迄移動する ios::binary ファイルをバイナリモードで開く 読み取り専用モードで開くには、下記の様に記述する。 std::ifstream fromFile("sample.txt"); std::ifstream fromFile; fromFile.open("sample.txt", std::ios::in); 下記に、シーケンシャルファイル sample.txt より、最初の 1 行分を読み込むコードを示す。 #include "stdafx.h" #include <iostream> #include <fstream> #include <string> int main() { std::string s = ""; std::ifstream fromFile; fromFile.open("sample.txt", std::ios::in); std::getline(fromFile, s); std::cout << s << std::endl; fromFile.close( ); return 0; }
猶、総ての行を読み込むには、ファイルの終端に達すると true に成る eof 関数(End of file)を利用す る。 std::ifstream fromFile; fromFile.open("sample.txt", std::ios::in); while (!fromFile.eof( )) { std::getline(fromFile, s); std::cout << s << std::endl; } fromFile.close( ); シーケンシャルファイルからのデータの読込では、CSV ファイルが使用される事が多い。其処で、下記 に、1 行分読み込んだ後、区切り文字(デリミタ)でデータを分割するコードを、下記に示す。 #include "stdafx.h" #include <iostream> シーケンシャルファイル sample.txt は デバッグ時には、ソースファイル(.cpp) と同じディレクトリに格納されて居る 物とする。
#include <fstream> #include <string> #include <sstream> int main() { std::string s = ""; std::ifstream fromFile; fromFile.open("sample.txt", std::ios::in); while (!fromFile.eof( )) { std::getline(fromFile, s); std::cout << s << std::endl; std::stringstream ss{ s }; std::string buf;
while (std::getline(ss, buf, ',')) {
std::cout << buf << std::endl; } } fromFile.close( ); } ■ 出力 ファイルにデータを書き込む時、下記のモードでファイルをオープンする(ios::out と ios::app と ios::trunc はシーケンシャルファイル、ios::binary はバイナリファイルに使用する)。 モード 意味 ios::out 出力用にファイルを開く ios::app 追加(アペンド)出力 ios::trunc 既存のファイルを上書きする ios::binary ファイルをバイナリモードで開く 下記に、シーケンシャルファイル sample.txt に、1 行分のデータを書き込むコードを示す(上書きモー ドなので元のデータは消去される)。 #include "stdafx.h" #include <iostream> #include <fstream> #include <string> int main() { std::string s = " Junko, F, 63, 165.2, 51.3"; std::ofstream toFile; toFile.open("sample.txt", std::ios::out); toFile << s << std::endl; toFile.close(); return 0; }
下記に、シーケンシャルファイル sample.txt に、1 行分のデータを書き込むコードを示す(追加モード なのでファイルの末尾に追加される)。 #include "stdafx.h" #include <iostream> #include <fstream> #include <string> int main() { std::string s = " Junko, F, 63, 165.2, 51.3"; std::ofstream toFile; toFile.open("sample.txt", std::ios::app); toFile << s << std::endl; toFile.close(); return 0; } ■ 書式設定
ostream、ofstream、ostringstream に関しては、ios(iostream は ios が include されて居る)、iomanip を include して、書式を設定する事が出来る。
#include <iostream> 若しくは #include <ios>
書式 値 解説 skipws 0x0001 ストリームの入力中,先頭の空白文字を読み飛ばす left 0x0002 出力を左寄せ right 0x0004 出力を右寄せ internal 0x0008 符号と数字の間にブランクを入れ出力幅一杯にする dec 0x0010 10 進表記(デフォルト) oct 0x0020 8 進表記 hex 0x0040 16 進表記 showbase 0x0080 数値の基数の表示 showpoint 0x0100 浮動小数点の出力で小数点、右端の 0、e を表示 uppercase 0x0200 浮動小数点の e 等を大文字で表示 showpos 0x0400 正の数値の前に+を表示 scientific 0x0800 実数値を浮動小数点表示 fixed 0x1000 固定小数点表示(デフォルト) unitbuf 0x2000 出力の度に総てのストリームをフラッシュ
stdio 0x4000 出力の度に stdout と stderr をフラッシュ
書式 解説 int width(int <長さ>); 出力幅制御 char fill(char <文字>); 空白を埋める文字 int precision(int <桁数>); 小数点以下の桁数(デフォルトは 6 桁。固定小数点の場合は、小数点 や符号を除いた全体の桁数に成り、表示出来ない時は浮動小数点表示 と成る)
#include <iomanip> 書式 解説 dec 10 進表記 endl 改行文字の出力 ends 空白文字の出力 flush ストリームのフラッシュ hex 16 進表記 oct 8 進表記 resetioflags(long f) f で指定されたフラッグを off setbase(int base) 基数を base にする
setfill(int ch) 文字 h で埋める setioflags(long f) f で指定されたフラッグを on setprecision(int p) 小数点以下 p 桁(デフォルトは 6 桁。固定小数点の場合は,小数点や符 号を除いた全体の桁数に成り、表示出来ない時は浮動小数点表示と成る) setw(int w) 出力幅を w ws 先頭の空白を読み飛ばす 使用例
#include <iostream> //std::right #include <iomanip> //std::setw(int w) int main()
{
double a=3.14159;
// 混在出来る
std::cout << std::setw(10) << std::right << a << std::endl; //output : " 3.14159" return 0; } ■ 補足 読み込みや書き込み失敗がメンバ関数 fail で確認出来るので、其のエラー処理を適宜入れると良い。 fstream にはメンバ関数 getline が有るが、使えないので基本的に使わない。代わりに、前述の様に、 std::string に有る getline 関数を使用する事が多い。 空白が連続して居て、読み辛いファイルの場合、演算子>>を使用する。例えば、下記の様にすると、空 白を飛ばして読める。 std::string buf = ""; std::istringstream sep(s); sep >> buf; sep >> buf; sep >> buf;