なまもの備忘録

気になったことをつらつらと書いていきます

C++でのファイルの入出力

2/25 17:28

C++でのファイルからの入力、ファイルへの出力の仕様がよく分からなくてもやもやする。検索をしてもどうもC仕様のやり方とC++仕様のやり方があるようで、この二つが混ざって出てくる上に痒いところに手が届かないサイトしかない。あまりにイライラするのでとりあえず今欲しい情報をまとめて調べて、後で忘れた時のために書いておくことにする。
ついでにフラフラとサイトを彷徨っていたら何やら良さそうなC++の本が紹介されていたのでメモ代わりに残しておくことにする。

Accelerated C++ - 効率的なプログラミングのための新しい定跡
Exceptional C++ - 47のクイズ形式によるプログラム問題と解法

まず、stdio.hのヘッダファイルを使った入出力の方法をまとめてみる。これはC言語関数辞典(http://www.c-tipsref.com/reference/stdio.html)に載っていたのでC言語様の入出力方法なのだろう。欲をいえば覚えることは減らしたいので文法は全てC++様のものにしたいのだが、面倒なので当分はこちらをまとめてこちらを使うことにする。
fopenでファイルを開いて、入出力関数でごにょごにょし、fcloseでファイルを閉じるのが一連の流れになる。
openの戻り値は事前に宣言したファイルポインタに入れる。これは、fopenが「開いたファイルの情報を持っているオブジェクト」のポインタを返す関数だからみたいだ。
ちなみにファイル型はstdio.hの中でtypedefによって定義されている型なので、stdio.hをincludeすれば宣言できる様になる。
つまり、test.dataを読み込もうとしたら

#include <stdio.h>
...
FILE * fp;
...
fp = fopen("test.data", "r");

のようなコードを書けば良い。この時、fopenの二つ目の引数の”r”は読出し専用モードで開くことを指定している。
このようなモード指定は他にもある。
f:id:purple-apple:20170205200133p:plain
(http://www.c-tipsref.com/reference/stdio/fopen.html)

今回僕が知りたいのは開いたファイルの情報を上書きするのではなく、その末尾に追加で情報を加える方法なのだが、”a”で指定できる追加書き込みがどうも欲しい機能を提供してくれそうだ。
write モードではファイルを消してしまう事になるので、ファイル を消さずに書き込みを行うには append モードを用いる。(http://www.wakhok.ac.jp/~kanayama/C/02/node165.html)とあるので、これでできそう。というか全部更新モードでいいじゃないか。まあエラーを吐かせたほうが云々というのはあるのだろうけど。

ちなみにファイルのクローズは

fclose(fp);

のように書くが、プログラム終了時にはオープンしたファイルは必ずクローズされるらしいので途中でモードを変更したい場合以外は特にする必要もないみたい。
ファイルからの情報の読み込みにはfscanfを使う。使う時は下のような感じ。

double one_data;
fscanf(fp,"%lf ",&one_data);
data[t][i] = one_data;

一つ目の変数で入力に使うオブジェクトのポインタを指定(これをストリーム(プログラム-入出力間のデータの流れ)をしていすると言うらしい)している。
二つ目の引数は書式文字列と言うらしい。

%[代入抑止文字][フィールド幅][長さ修飾子]変換指定子 ※[]内は省略可能

という形式で記述する。代入抑止文字の部分には、もしを書くと指定した文字が読み込まれずに破棄される。例えば、%2cとやると先頭の2文字が破棄されるらしい。
長さ修飾子については以下のような感じで、引数の型を指定している。なんで長さなのかは謎。知っている方いたら是非とも教えていただきたいです。
[f:id:purple-apple:20170205200351p:plain]
(https://ja.wikipedia.org/wiki/Scanf)
変換指定子については以下
[f:id:purple-apple:20170205200406p:plain]
(https://ja.wikipedia.org/wiki/Scanf)
読み取った引数を戻す際に変換を加えることができる。
3つ目の引数には適切な方の変数を入れて、以降この変数に入ったデータを扱う。

for(int t = 0; t < TIME; t++){
          for(int i = 0; i< CELL ;i++){
            fscanf(fp,"%lf ",&one_data);
            data[t][i] = one_data;
          }
        }

のように使用すると、fpがさすオブジェクトのデータを勝手に順々にスキャンしていってくれる。また、改行は特に意識されないみたい。
とりあえずこの辺まで調べて満足したので終わり。

3/18 C++仕様の入出力についても簡単にメモしておく。

#include <fstream>
//入力
std::ifstream ifs(“ファイルパス”); //ifsにファイルの内容が読み込まれる
std::getline(ifs,line);//lineにifsの内容を1行ずつ読み込む

//出力
std::ofstream ofs(“ファイルパス”);
off << “書き込みたい文字列等” << std::endl;

軽いプログラムの時はこっちのほうが楽そう。