【C++】ファイルの読み込みまとめ

公開日: : 最終更新日:2014/08/14 C/C++

スポンサーリンク

C++におけるファイル読み込みのまとめ

ファイルの開き方

C++でファイルを開くときはfstreamヘッダをインクルードする必要があり、この中のifstream(インプットストリーム)を使用します。例えば「test.txt」を開くときは以下のようになります。

std::ifstream ifs(“test.txt”);
std::string str;
ifs>>str;
std::cout<<str<<std::endl;

ファイルを閉じるときはcloseメソッドを使えばよいが、特に使用しなくても勝手に閉じるので使わない場合が多いです。

読み込みに失敗したかどうか判定するにはfailメソッドを使えばできます。

if(ifs.fail())
{
	std::cout<<”読み込みに失敗しました”<<std::endl;
}

また、バイナリで開くなどの指定も可能。

モード 意味
ios::app 追加出力
ios::ate 開く時にEOFまで移動する
ios::binary ファイルをバイナリモードで開く
ios::in 読み込み専用で開く
ios::out 出力用にファイルを開く
ios::trunc 既存のファイルを上書きする

これとは別にC言語でよければfopenでも簡単に開けます。

値の取得方法

>>演算子を使う

>>演算子を用いて値を取得することができる

std::ifstream ifs(“test.txt”);
int a,b,c;
char split;
ifs>>a>>split>>b>>split>>c;

ただ、

2,4,6,9

のようなデータならよいですが、

3,,5,

のように区切りの間に空白部分があるとあやしくなってしまいます。

1行ずつ読み込む

std::getline関数を用いることで1行読み込みが行えるため、その文字列から数値に落とし込みます。

std::ifstream ifs(“test.txt”);
std::string str;
while(getline(ifs,str))
{
	std::cout<< str << std::endl;
}

上の例はgetlineの戻り値はifsなのでファイルの終端まで読み込みを行うことができます。

stringにはc_strメソッドとdataメソッドの2つの方法のいずれかでchar*への変換が可能となっています。

(両者の違いについてC++標準文字列:c_str, data, operator[])

取得した文字列をどうやって数値に戻していくのか検討したいと思います。

(1) sscanfを用いる方法(C言語)

C言語の標準ライブラリに定義されている関数です。

int sscanf(const char *str, const char *format, ... );

…の部分は可変引数と呼ばれ、文字通り任意の個数だけ引数を指定できる。これはprintfなどでも使用されています。

これを利用して得られたchar*を分解します。

例えば読み込んだデータが

int , int , int ,float

といった並びになっていれば

int a,b,c;
float d;
sscanf(str.c_str(),“%d,%d,%d,%f”,&a,&b,&c,&d);

とすればめでたく数値を読み込めます。

(2)文字列から数値に変換する方法

(2-1)文字の解析

sscanfでは一度に文字を数値に変換できてしまえましたが、その他の方法では、その前に文字列を数値のものに分割する必要のあるケースも多いです。例えばCSVファイルなどのカンマ区切りのものはカンマとデータそのものを分離させる必要があり、さらに文字列を数値データに直す必要があります。

例)

“1,6,-2” (←文字列)

“1”、”6”、”-2”  (←文字列×3)

1、6、-2 (←数値)

この問題を解決するにはどうすればよいのか。

A. getlineによる分割

getlineは指定文字リテラルで文字を分割することもできます。3つめの引数にカンマなどの文字を指定することで可能。ただし、この際に使用する入力文字列ストリームistringstreamを使用するにはsstreamをインクルードする必要があります。

#include<sstream>
…
std::ifstream ifs(“test.txt”);
std::string str;
while(getline(ifs,str))
{
	std::string tmp;
	std::istringstream stream(str);
	while(getline(stream,tmp,’,’))
	{
		std::cout<< tmp << std::endl;
	}
}

例)

test.txt
2,5,4
2
5
4

ただ、このままだと文字列ということに変わりはないです。

B. splitによる分割(指定キーワードによる文字列分割)

残念ながらC++には想像しているようなSplitメソッドは存在しないようで、自作で作るかBoostライブラリを使用するしかないらしいです。

が、しかし、それについて解決策を記述されている方も多く、そちらを参考にした方がいいかもしれません。

(2-2)数値への変換
A. atoi,afofなどを用いる方法(C言語)

文字列を数値に変換する手法としてC言語(stdlib.h)にあるatoi関数やatof関数を用いるものがあります。(iはintのi)

ただし、これらの手法の問題点は数値に変換したい文字列が数値でなかった場合の例外発生がないということです。

int tmp1 = atoi(“123”); //○
int tmp2 = atoi(“ABC”); //×

なので、これを使う場合はちゃんと数字かどうかの判定が欠かせないです。

B. strtodを用いる手法(C言語)

この関数もstdlibに宣言されている関数ですが、atoiなどとの違いはエラー検出があるという点です。

double strtod(const char *s, char **endptr);

はじめの引数には変換したい文字列、2つ目の引数にはエラーの場合の出力用のようです。

doubleへの変換が失敗した場合失敗した個所の文字列のポインタが格納されるようになっています。

char *tmp1 = "1.23";
char *err1=NULL;
char *tmp2 = "1.23ABC";
char *err2=NULL;
char *tmp3 = "ABC1.23DEF";
char *err3=NULL;
double x1 = strtod(tmp1,&err1);
double x2 = strtod(tmp2,&err2);
double x3 = strtod(tmp3,&err3);
cout << "x1=" << x1 << "," << err1 << endl;
cout << "x2=" << x2 << "," << err2 << endl;
cout << "x3=" << x3 << "," << err3 << endl;
x1=1.23,
x2=1.23,ABC
x3 =0,ABC1.23DEF
(※3つめは失敗)

文字列を含んでいても一部では変換がうまくいっていますが、冒頭から文字列の場合はうまくいかない様子です。たとえ変換に失敗しても0が帰ってくるだけのようです。

いずれにせよ第2引数の値などでエラー判定が可能なため安心して数値変換が行えるようになっています。ちなみに第2引数をNULLとしてしまっても変換不可能な処理を行わないだけで動きます。

C. C++/CLIを用いる手法

VisualStudioであればプロジェクトのプロパティで「共通言語ランタイムサポート」を「共通言語ランタイムサポート(/clr)とするとコンソールアプリケーションでもSystem::Stringが使えるようになるのでこれを用いて1行の文字をカンマなどの指定の文字で分割(Splitメソッド)し、String→int,floatなどで値の取得ができます。

char *tmpstr = "123";
System::String ^str = gcnew System::String(tmpstr);
try
{
	int tmp = int::Parse(str);
	System::Console::WriteLine(tmp);//123
}
catch(System::Exception^){}

try~catchは例外処理。doubleやfloatに変換したいときは『int::』の部分を『float::』や『double::』にすればできます。

もしこの方法を用いるのなら読み込みからこちらの文法を使用したほうがよいかもしれないです。

図はVisualStudio 2008のものです。
memrun2.png

スポンサーリンク
Amazon
  • このエントリーをはてなブックマークに追加

関連記事

コンソールアプリケーションでC++/CLIの関数を使う

今時(?)なかなか使っている人がいるかどうかわかりませんが、VisualStudio(2008)で「

記事を読む

no image

【C++】文字列のcontainsメソッドによる比較

C++/CLIなどではStringのContainsメソッドが便利ですが、純粋なC++のstring

記事を読む

【C言語】fopenが失敗するエラー

ファイル操作に使うfopenがどうしても失敗してしまい困っていました。既に開かれているファイルを開く

記事を読む

【C言語/C++】フォルダ作成を行う

C言語、C++でフォルダを作成するには『direct.h』にある『_mkdir』関数を使うことで実現

記事を読む

【C++/CLI】フォームアプリケーションでコンソール画面を出現させる

プロジェクトのプロパティを開いて「構成プロパティ」→「リンカ」→「システム」の「サブシステム」を「コ

記事を読む

【C言語】文字列に指定の文字列が含まれるか調べる

ある文字列に指定の文字列が含まれるかどうかを調べるにはstring.hにあるstrstr関数を使いま

記事を読む

【C言語/C++】ファイルをCSV形式でfprintfを使って保存・書き込みする

数値計算などをC言語でプログラミングするとき、その演算結果をファイルとして保存する必要性がでてくるこ

記事を読む

【C言語】printfのような関数を作る

C言語でよくつかわれるprintfでは例えば int a,b,c; … printf(

記事を読む

【C言語/C++】はてなの演算子の三項演算子について

C言語などのサンプルにたまに出てくるはてな(?)の演算子は 『?』と『:』の2つで1つの演算子であ

記事を読む

【C言語】fscanfでファイルを1行ずつ読み込む

C言語のfscanfでCSV形式(単純なカンマ区切り)のファイルを読み込むサンプル。 基本的なこと

記事を読む

Comment

  1. pochifx より:

    9行目は
    std::istringstream stream(str);
    だと思う。

  2. ががんぼ より:

    > 9行目は
    > std::istringstream stream(str);
    > だと思う。
    ご指摘ありがとうございます。
    訂正いたしました。

【Unity】他のスクリプトを一括で取得して有効化・無効化を制御する

Unityを使っていて他のスクリプトを一時的に停止させたいと思ったので

テレビの録画をPCやNASで共有する

今までテレビはテレビ用のモニターで見ればいいやと思っていたのですが、さ

【DeepLearning】物体検出手法のSSD(Keras版)を試す (Ubuntu14.04)

はやりのディープラーニングの物体検出手法の一つであるSSDのサンプルを

【Laravel5】既存のDBからデータを取得して表示する

はじめに 今まで作ったWebサイトをLaravel5で見れるようにし

【C++/OpenCV】cv::Matの画像にインパルスノイズを付加する

OpenCVで画像にノイズを付け足したいと思って調べたところ、Pyth

Intel Corei7-7700TでHTC Viveの動作確認

はじめに HTC ViveというVRヘッドセットで遊んでみたのでその

【Python】フォルダ内のカッコ付き数字ファイルを一括でリネームするスクリプト

はじめに タイトルどおりなのですが、指定フォルダ内のファイルのファイ

→もっと見る

  • Author : ががんぼ
    プログラミングやWeb関係で気付いたことについてメモしていく予定。だいたいが備忘録ですが、自分でサンプルを作って動かしてみたりしています。
PAGE TOP ↑