簡単なテキストファイル入出力例
テキストファイル入出力サンプルプログラムをC++で作成してみた。
#include
<iostream>
#include
<fstream>
using
namespace std;
int
main(){
cout << "Input File Name = ";
char
nm[100];
cin >> nm;
ifstream fin;
fin.open(nm);
cout << "Output File Name = ";
cin >> nm;
ofstream fout;
fout.open(nm);
char str[1000];
while(!fin.fail()){
char
str[1000];
fin.getline(str, 1000);
fout << str << endl;
}
fin.close();
fout.close();
return
0;
}
上のプログラムを、データファイルData.txtを入力ファイル、Check.txtを出力ファイルとして実行してみる。
Data.txtは、図1のように用意されている。
図1(各行先頭の青字で表示されている1〜10の数字は、エディタ画面における行番号である)
プログラムを図2のように実行する。
図2
上の実行例は、openSUSE 13.2 におけるものであるが、openSUSE 13.2 における g++ のインストールの方法を説明したウェブサイトも用意した。
図2の実行例では、ファイルData.txtは、プログラムと同じフォルダに用意されていて、出力ファイルもプログラムと同じフォルダに出力される。プログラムの実行時カレントディレクトリがプログラムソースファイルと同じディレクトリになっている。
図1の入力ファイルに対して、プログラムの実行終了後の出力ファイルは図3のようになっている。
図3
上のプログラムにおいて
fin.getline(str, 1000);
を
fin.getline(str, 5);
に変更した次のプログラムを、図2と同じように実行してみる。
#include
<iostream>
#include
<fstream>
using
namespace std;
int
main(){
cout << "Input File Name = ";
char
nm[100];
cin >> nm;
ifstream fin;
fin.open(nm);
cout << "Output File Name = ";
cin >> nm;
ofstream fout;
fout.open(nm);
char str[1000];
fin.getline(str, 5);
while(!fin.fail()){
fout << str << endl;
fin.getline(str, 5);
}
fin.close();
fout.close();
return
0;
}
このとき、出力ファイルは図4のようになる。
図4
ファイルからの読み込み
fin.getline(str, 5);
において、2番目の引数の値5より1少ない4番目の文字まで読み込まれると、4番目の文字までがstrに設定されて、関数
fin.fail()
の値がtrueに設定されることがわかる。
最初のプログラム例では、
fin.fail()
の値は、ファイルからの読み込み
fin.getline(str, 1000);
の実行において、ファイルの最後の文字列が読み込まれた後、trueに設定されている。このtrueに設定されるタイミングはVisual C++では少し異なるが、別のウェブサイトで説明した。
テキストファイルから1つずつの値を読み込むサンプルプログラムを、以下のように作成した。
#include
<iostream>
#include
<fstream>
using
namespace std;
int main(){
cout << "Input File Name = ";
char
nm[100];
cin >> nm;
ifstream fin(nm);
cout << "Output File Name = ";
cin >> nm;
ofstream fout(nm);
int v;
fin
>> v;
while
(!fin.fail()){
fout << v << endl;
fin
>> v;
}
fin.close();
fout.close();
return
0;
}
標準入出力cin、coutと同じ使い方である。
図5のデータファイルに対して、
図5
図6のように実行すると、
図6
図7の出力ファイルを得る。
図7
空白などで区切られた文字列から、空白で区切られた部分文字列を取り出す
図8のファイル
図8
を入力ファイルとするとき、空白で区切られた部分文字列を取り出すことを考える。例えば、3行目の文字列「aa f gg 」から、「aa」、「f」、「gg」を取り出す。
部分文字列を取り出すプログラム例として次のものを作成した。
#include
<iostream>
#include
<fstream>
#include
<sstream>
using
namespace std;
string
SeekStr(char * cstr, int pos){
stringstream strfile(cstr);
string
vs;
for (int i = 0; i
<= pos; i++){
if
(strfile.eof()){
vs
= "";
break;
}
else{
strfile >> vs;
if
(i < pos) vs =
"";
}
}
return
vs;
}
int main(){
cout << "Input File = ";
char
nm[100];
cin >> nm;
ifstream fin(nm);
cout << "Output File = ";
cin >> nm;
ofstream fout(nm);
while
(!fin.fail()){
char
vcs[1000];
fin.getline(vcs, 1000);
for
(int i = 0; i < 10; i++)
fout << i <<
":<" << SeekStr(vcs, i) << "> ";
fout << endl;
}
return
0;
}
関数 string SeekStr(char * cstr, int pos) によって、cstr 内の pos 番目の部分文字列が取り出される。pos の値が大きすぎて該当する部分文字列がないときは、空白文字列が返される。
図8のファイルに対して上のプログラムを図9のように実行する。
図9
出力ファイルは図10のようになっている。
図10
空白などで区切られた部分文字列が取り出されていることがわかる。
数値を表す文字列を数値に変換する
数値を表す文字列を数値に変換する場合において、Cの関数を用いる方法とC++のstringstreamオブジェクトを用いる方法の処理時間の比較を行うプログラムを作成した。
#include
<iostream>
#include
<sstream>
#include
<time.h>
#include
<stdlib.h>
using
namespace std;
// Conversion
of string to int
int
str2i(string str){
stringstream sstrm(str);
int iv;
sstrm >> iv;
return
iv;
}
// Conversion
of string to double
double
str2d(string str){
stringstream sstrm(str);
double
dv;
sstrm >> dv;
return
dv;
}
int
main(){
cout << "Start..." << endl;
const int n = 1000000;
string
* vstr = new string[n], * vstrd
= new string[n];
time_t * t0 = new time_t;
time(t0);
//
// Set
string data
//
for (int i = 0; i
< n; i++){
ostringstream sstrm, sstrmd;
sstrm << i;
vstr[i] = sstrm.str();
sstrmd << 0.1 * i;
vstrd[i] = sstrmd.str();
}
time_t * t1 = new time_t;
time(t1);
double
diff_time = difftime(*t1,
*t0);
cout << "string values..." << endl;
for (int i = n - 3; i < n; i++)
cout << i << ":
" << vstr[i]
<< " "
<< vstrd[i] << endl;
cout << "diff time = " << diff_time << "s for " << n * 2 <<
"values" << endl;
//
// Convert
string to char*
//
char
** cstr = new char*[n], ** cstrd
= new char*[n];
for (int i = 0; i
< n; i++){
cstr[i] = new char[100];
for
(int j = 0; j < vstr[i].length(); j++)
cstr[i][j] = vstr[i][j];
cstr[i][vstr[i].length()] = 0;
cstrd[i] = new char[100];
for
(int j = 0; j < vstrd[i].length(); j++)
cstrd[i][j] = vstrd[i][j];
cstrd[i][vstrd[i].length()] = 0;
}
cout << endl <<
"(char *) values..." << endl;
for (int i = n - 3; i < n; i++)
cout << cstr[i] << " " << cstrd[i] << endl;
//
// Convert
char* to int or double
//
int * ivalues = new int[n];
double
* dvalues = new double[n];
char
* ept;
int gn_rep = 20;
cout << endl <<
"Conversion by C functions..." << endl;
time(t0);
for (int k = 0; k < gn_rep; k++)
for
(int i = 0; i < n; i++){
ivalues[i] = atoi(cstr[i]); // C
function
dvalues[i] = strtod(cstrd[i], &ept); // C
function
}
time(t1);
diff_time = difftime(*t1, *t0);
cout << "diff time/C = " << diff_time << "s for atoi and strtod functins." << endl;
cout << "Converted values..." << endl;
for (int i = n - 3; i < n; i++)
cout << ivalues[i] << " " << dvalues[i] << endl;
//
// Convert
string to int or double
//
cout << endl <<
"Conversion by stringstream objects..."
<< endl;
time(t0);
for (int k = 0; k < gn_rep; k++)
for
(int i = 0; i < n; i++){
ivalues[i] = str2i(vstr[i]); // Defined
above
dvalues[i] = str2d(vstrd[i]); // Defined
above
}
time(t1);
diff_time = difftime(*t1, *t0);
cout << "diff time/S = " << diff_time << "s for stringstream
objects." << endl;
cout << "Converted values..." << endl;
for (int i = n - 3; i < n; i++)
cout << ivalues[i] << " " << dvalues[i] << endl;
cout << endl <<
"Deleting objects..." << endl;
delete
[] vstr;
delete
[] vstrd;
delete
t0;
delete
t1;
for (int i = 0; i
< n; i++){
delete
[] cstr[i];
delete
[] cstrd[i];
}
delete
[] cstr;
delete
[] cstrd;
delete
[] ivalues;
delete
[] dvalues;
return
0;
}
上のプログラムをVM VirtualBox上にインストールしたopenSUSE 13.2において実行すると、図11のようになった。
図11