C++ ファイル操作 書いて覚えるための初心者自己中記事①
ファイルを扱うのに便利な標準ライブラリ
#include <cstdio> 便利な関数が入っている
#include <fstream> fstreamクラスが入っている
Xcode 8.3.3 で file.open で作ったはずのファイルがどこにもない・・・
・・できた。
xcodeでビルドした時にxcode内でいつも結果を見てるから勘違い。
ビルドされたファイルを実行しないとダメなのね。
---------------------------------------------------
int main(){
fstream file; //fstreamクラスのオブジェクト作成
file.open("test.txt",ios::out); //メンバ関数openに渡す引数は ファイル名 フラグ(ios::out はファイルへ書き出すの意味)
if(! file.is_open()){ //メンバ関数is_open は返り値がbool型でファイルを開けなかったりエラーになったらflase
cout << "NG" << endl;
return EXIT_FAILURE;
}
file << "ファイルに書き込み" << endl; //fstreamオブジェクトのfileに書き込む内容を渡す
file.close();
}
---------------------------------------------------
ファイルはユーザーの自分のフォルダ内に出来上がりました。
fstreamクラスのオブジェクトを作り、そのオブジェクトでメンバ関数 open(ファイル名,フラグ) を呼び出して test.txt を書き出し目的で開く、とする。
同じくメンバ関数の is_open( ) で open関数が成功したかどうかを確認。
失敗ならmain関数を抜けるための EXIT_FAILURE をreturnさせる。
EXIT_FAILUREのFAILUREってどう読むんだ?
フェイエルって聞こえる。
準備ができたら fstreamクラスのオブジェクト fileに << を使って書き込みたい内容を記述する。
最後にメンバ関数 close で当該ファイルを閉じて終了。
実際にはfstreamクラスのデストラクタでファイルは閉じられるそうですが、それ以前に必要なくなったら閉じるのが良いそうです。
ちなみにflushはfstreamクラスのメンバ関数にあるらしいので
---------------------------------------------------
file << "ファイルに書き込み";
file.flush();
---------------------------------------------------
こんな感じにも出来るとのこと。
色々書き込んで最後だけ file.flush(); でOK
fstreamクラスのメンバ関数open( ) を使った際のフラグについて
ios:out ファイルへの書き出し
ios::in ファイルから読み込み(メモリへの入力)
ios::binary バイナリモードで開く
ios::trunc ファイルが存在している場合にそれを破棄してから開く
ios::app 常にファイルの末尾に書き出し
ios::ate ファイルを開いて末尾に移動
フラグは複数同時に指定できる。その場合は , ではなく | で区切る。
ファイルから入力(読み込み)
---------------------------------------------------
int main(){
fstream file; //fstreamクラスのオブジェクト作成
file.open("test.txt",ios::in);
if(! file.is_open()){
cout << "NG" << endl;
return EXIT_FAILURE;
}
string str;
getline(file,str);
cout << str << endl;
file.close();
}
---------------------------------------------------
getline関数でstringクラスのオブジェクトに渡してますね。
以前にgetline関数を習った時に気になってたことがあって
その内容をそのまま下にコピペ
=====================================
getline 関数
---------------------------------------------
int main(){
string str;
getline(cin,str);
cout << str << endl;
}
---------------------
(結果)
aaa
aaa
---------------------------------------------
入力から1行を拾ってstringクラスのオブジェクトに入れることができる。
入力から1行を拾って。
入力から1行を拾って・・・?
=====================================
ファイルからの読み込みを入力と言ってるじゃないですか。
ってことはファイルからの入力に対して1行だけってことじゃないのかな?
試してみよう。
test.txt
ファイルに書き込み1行目
ファイルに書き込み2行目
ファイルに書き込み3行目
を読み込んだら
ファイルに書き込み1行目
だけだった。
やっぱりそうなんですね。
疑問解決。
戻ります。
このようにファイルから入力されたデータを一時的に保存しているのもメモリですが、特にこの場合はバッファと言います。
今回の場合はstrがバッファらしいです。
今までcin >> 変数 とかやっていた時の 変数 もバッファなんですね。
入力データなので。
fstreamクラスのメンバ関数open の引数、フラグについて
なんでも ios::in|ios::out で読み書きができると書いていあるので試しても、うまくできない。
具体的には読めてない。書き込みはできる。
出力はできる。
入力ができない。
---------------------------------------------------
int main(){
fstream file; //fstreamクラスのオブジェクト作成
string str;
file.open("test.txt",ios::in|ios::out|ios::ate);
if(! file.is_open()){
cout << "NG" << endl;
return EXIT_FAILURE;
}
getline(file,str);
cout << str << endl;
file << "もじれつ文字列" << endl;
getline(file,str);
cout << str << endl;
file.close();
}
---------------------------------------------------
結果空白
何かを勘違いしているはず・・・
test.txt にはどんどんと文字列が追加されて言ってるんだけどなぁ・・
---------------------------------------------------
int main(){
fstream file; //fstreamクラスのオブジェクト作成
string str;
file.open("test.txt",ios::in|ios::out/*|ios::ate*/);
if(! file.is_open()){
cout << "NG" << endl;
return EXIT_FAILURE;
}
getline(file,str);
cout << "①" << str << endl;
file << "もじれつ文字列" << endl;
getline(file,str);
cout << "②" << str << endl;
file.close();
}
----------------------------
(結果)
①もじれつ文字列
②
---------------------------------------------------
test.txt の一行目が空白になってた。
でも②はなんで・・・?
ちょっと今は理由がわからない。まだファイル操作始まったばかりだから。うん。
ios::binary バイナリモードで開く について
ファイル操作の際に行われる入出力は二つのモードのどちらかだ。
テキストモード
バイナリモード
デフォルトはテキストモード
ios::binary をフラグにした時だけはバイナリモード
違いを説明するために必要な項目は改行コード
改行コードは環境によっていくつかあり
windowsでは \r (13) \n (10)
Macでは \r (13)
Unix / Linaxでは \n (10)
とバラバラ。
テキストモードはこの改行コードを自動で読み替えてくれる。
バイナリモードの場合は一切しない。純粋にメモリの値が入出力される。
C++ では10進数・16進数・8進数をそれぞれ表現できる
---------------------------------------------------
int main(){
int n;
n = 214; //10進数
n = 0xD6; //16進数
n = 0326; // 8進数
}
---------------------------------------------------
どれも数値に違いないので普通に使える。
ios::binary
バイナリデータの
出力 .write ( (const char*)buf , size ); 送り側のアドレスとバイト数
入力 read
---------------------------------------------------
int main(){
fstream file;
file.open("binary.txt",ios::out|ios::binary);
if(!file.is_open()){
return EXIT_FAILURE;
}
int n = 0x41424344;
file.w rite( (const char*)&n,sizeof n);
file.close();
}
(結果)
DCBA
---------------------------------------------------
fstreamクラスのメンバ変数 writeの引数がなんかすごい。
const char* にキャストするために16進数入れた変数に & つけて、
( const char*)&n なんか琴線に触れた。
結果を見ると逆になっている。
これは下の桁から記録されたから?
つまり 0x44 0x43 0x42 0x41 と記憶されているということらしい。
この順番は環境依存なのだそうです。
このバイトの順番の違いにも名前があってバイトの順番のことを
バイトオーダー と言います。
そして私の環境だった順番が逆のものをリトルエンディアン
そして順番通りのものをビッグエンディアンと言います。
バイトオーダーはCPUによって変わる。
セーブデータ改造ツールとかに書いてあったのはこの事かぁ〜〜
いままでのfile << "文字列" << endl; 的なのをやると
---------------------------------------------------
int main(){
fstream file;
file.open("binary.txt",ios::out|ios::binary);
if(!file.is_open()){
return EXIT_FAILURE;
}
int n = 0x41424344 ;
//file.wri te( (const char*)&n,sizeof n);
file << n;
file.close();
}
-------------------
(結果)
1094861636
---------------------------------------------------
こうなります。
さっきはメモリのデータをそのままファイルに出力したので .txt ファイルを開くと文字コードとして扱われて DCBA と表示されました。
今回は file << n;
とした為10進数の10バイトの文字列として出力されたそうです。
0x41424344 を10進数で表すと 1094861636 です。
入力(読み込み)
.read( (char*)buf ,size); 引数は受け取り先のアドレスとサイズ
受け取り先のサイズって必要なの?
---------------------------------------------------
int main(){
fstream file;
file.open("binary.txt",ios::in|ios::binary);
if(!file.is_open()){
return EXIT_FAILURE;
}
int n;
file.read( (char*)&n ,sizeof n); //read関数はコチラ
cout << n << endl;
file.close();
}
(結果)
1094861636
---------------------------------------------------
とにかくできた。
出力時は16進数でだったけど、10進数で来た。
眠い。
とりあえずここまで。