テキストファイル入出力
行単位の読み込み
テキストファイルからの読み込みを行単位で文字列として行うと便利なことがある。そのためのクラス型RdTxtLnを用意した。以下に宣言内容を示す。
class RdTxtLn {
public:
FILE * fin;
int iCond; // 0: OK, 1: End of File, 9: Open Error, -1: Not initialized
string s;
RdTxtLn(): iCond(-1) {}
//
// nmに読み込み用テキストファイル名を設定
// オープンに成功すればiCondの値は0が設定される。
//
RdTxtLn( string nm );
virtual ~RdTxtLn();
void open( string nm );
void close();
//
// メソッドreadlineを1回呼び出すと
// ファイルから1行分がstrに読み込まれる
//
int readline( string & str );
};
これはヘッダーファイルmyLib.hに宣言されているが、ヘッダーファイルmyLib.hとそのソースファイルmyLib.cppはこのウェブサイトの最後に示す。
ファイル名を設定したstring型変数nmによって
RdTxtLn rd( nm );
とRdTxtLn型オブジェクトrdを定義すると、rdによってnmの指し示すファイルから1行単位でデータを読み込むことができる。読み込みはメソッドreadline()をstring型変数sを引数として
rd.readline( s );
と実行すると、1行分のデータがsに設定される。sに設定されている文字列から、空白(半角)あるいはタブで区切られたipos番目の部分文字列を取り出す関数として
string SeekStr( string s, int ipos );
が用意されている。
文字列の表わす数値に変換する関数として
int strToInt( string s );
double strToDouble( string s );
が用意されている。
1行単位でデータを読み込むので、行の先頭に置かれた文字によってデータの始まりと終わりを示すことができる。図1のデータの場合、データは/で始まる行によって区切られている。
図1
データの読み込みは、string型変数sに設定された文字列からSeekStr関数によって2つのデータを取り出すことを以下のように行っている。
for (int i = 0; i < N; i++) {
rd.readline( s );
x[i] = strToDouble(SeekStr(s, 0));
y[i] = strToDouble(SeekStr(s, 1));
}
RdTxtLn型を用いたプログラム例を以下に示す。
#include "stdafx.h"
#include <iostream>
#include "myLib.h"
using namespace std;
using namespace myLib;
int _tmain(int argc, _TCHAR* argv[])
{
//
// 入力用テキストファイル名と入力ストリームの設定
//
cout << "Input data file = ";
string fin_nm;
cin >> fin_nm;
RdTxtLn rd( fin_nm );
if (rd.iCond != 0){
cout << "Opening input data file failed." << endl;
cout << "Input any number to exit." << endl;
double x;
cin >> x;
return 9;
}
//
// 出力用テキストファイル名と出力ストリームの設定
//
cout << "Output file = ";
char fout_nm[200];
cin >> fout_nm;
ofstream fout( fout_nm );
fout << "Input data file = " << fin_nm << endl << endl;
//
// 入力ファイルの先頭部分("/"で始まる行まで)の読み飛ばし
//
string s;
int ick = 0;
do{
rd.readline( s );
if (s.size() > 0)
if (s[0] == '/') ick = 1;
}while( ick == 0 );
//
// データ数Nを数える
//
int N = 0;
ick = 0;
do {
rd.readline( s );
if (s[0] == '/'){
ick = 1;
} else {
N++;
}
} while (ick == 0);
//
// 入力ファイルの先頭に読み込み位置を戻す
//
rd.close();
rd.open(fin_nm);
if (rd.iCond != 0){
cout << "To re-open the inpur file failed." << endl;
return 9;
}
ick = 0;
do {
rd.readline( s );
if (s.size() > 0)
if (s[0] == '/')
ick = 1;
} while (ick == 0);
double * x, * y;
x = new double[N];
y = new double[N];
for (int i = 0; i < N; i++) {
rd.readline( s );
x[i] = strToDouble(SeekStr(s, 0));
y[i] = strToDouble(SeekStr(s, 1));
}
fout << "\n" << "Data..." << endl;
for (int i = 0; i < N; i++) {
fout << i << ": x = " << x[i] << " \ty = " << y[i] << endl;
}
double sx = 0.0;
double sy = 0.0;
double sxx = 0.0;
double syy = 0.0;
double sxy = 0.0;
for (int i = 0; i < N; i++){
sx += x[i];
sy += y[i];
sxx += sqr(x[i]);
syy += sqr(y[i]);
sxy += x[i] * y[i];
}
double meanX = sx / N;
double meanY = sy / N;
double varX = (sxx / N) - sqr(meanX);
double varY = (syy / N) - sqr(meanY);
double sdX = sqrt(varX);
double sdY = sqrt(varY);
double Cov = (sxy / N) - (meanX * meanY);
double r = Cov / (sdX * sdY);
fout << endl;
fout << "mean of x = " << meanX << endl;
fout << "mean of y = " << meanY << endl;
fout << "Variance of x = " << varX << endl;
fout << "Variance of y = " << varY << endl;
fout << "SD of x = " << sdX << endl;
fout << "SD of y = " << sdY << endl;
fout << "Covarince = " << Cov << endl;
fout << "Correlation = " << r << endl;
double uvarX = N * varX / (N - 1);
double uvarY = N * varY / (N - 1);
double uCov = N * Cov / ( N - 1);
fout << endl;
fout << "Unbiased Var of x = " << uvarX << endl;
fout << "Unbiased Var of y = " << uvarY << endl;
fout << "Unbiased Cov = " << uCov << endl;
fout << "SD(uVarX) = " << sqrt(uvarX) << endl;
fout << "SD(uVarY) = " << sqrt(uvarY) << endl;
rd.close();
fout.close();
delete [] x;
delete [] y;
return 0;
}
上のプログラムの実行時のコンソールは次のようになっている。
図2
ファイル名を設定して、計算が終了するとコンソール画面は消える。上の場合の出力ファイルtemp.txtはエディタで開くと図3のようになっている。
図3
上のプログラム例は圧縮ファイルReadLNFile.zipとして用意した。圧縮ファイル名ReadLNFile.zipをクリックしてダウンロードできる。ダウンロードしたファイルはファイル名を右クリックして表示されるメニュから「展開」あるいは「解凍」などを選ぶと解凍できる。解凍したファイルはVisual C++ 2010から開くことができる。
ヘッダーファイルmyLib.hとそのソースファイルmyLib.cppも以下に示しておく。なお、ヘッダーファイルとそのソースファイルについての一般的な説明を<岡本安晴「大学生のための心理学VC++プログラミング入門」勁草書房>の「10.2 ヘッダーファイルとソースファイル」で行っているが、p.139において既存のそれらのファイルの利用法について説明している。
=============== myLib.h ====================
#ifndef MYLIB_CK
#define MYLIB_CK
// 2009.01 Y.Okamoto
#include <iostream>
#include <fstream>
#include <sstream>
namespace myLib {
using namespace std;
//
// x の平方を返す
//
double sqr( double x );
//
// 文字列sの表す整数値を返す
//
int strToInt( string s );
//
// 文字列sの表す実数値を返す
//
double strToDouble( string s );
//
// 空白文字(半角)かタブであればtrueを返す。
//
bool check_c( char c );
//
// 空白で区切られた文字列からなるstring型sに
// 含まれるipos番目の文字列を返す
//
string SeekStr( string s, int ipos );
//
// テキストファイルから1行ごとに読み込むためのクラス型
//
class RdTxtLn {
public:
FILE * fin;
int iCond; // 0: OK, 1: End of File, 9: Open Error, -1: Not initialized
string s;
RdTxtLn(): iCond(-1) {}
//
// nmに読み込み用テキストファイル名を設定
// オープンに成功すればiCondの値は0が設定される。
//
RdTxtLn( string nm );
virtual ~RdTxtLn();
void open( string nm );
void close();
//
// メソッドreadlineを1回呼び出すと
// ファイルから1行分がstrに読み込まれる
//
int readline( string & str );
};
} // myLib
#endif
==================================
============= myLib.cpp ==============
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include "myLib.h"
namespace myLib {
using namespace std;
double sqr( double x ){
return x * x;
}
//
// 文字列sの表す整数値を返す
int strToInt( string s ){
istringstream istrm(s);
int i;
istrm >> i;
return i;
}
//
// 文字列sの表す実数値を返す
//
double strToDouble( string s ){
istringstream istrm(s);
double d;
istrm>> d;
return d;
}
bool check_c( char c ){
if ( (c == ' ') || (c == '\t') ){
return true;
} else {
return false;
}
}
//
// 空白で区切られた文字列からなるstring型sに
// 含まれるipos番目の文字列を返す
//
string SeekStr( string s, int ipos ){
string vstr = "";
int sLength = s.size();
if (sLength <= 0){
return vstr;
}
int istart, iend;
if (ipos == 0){
istart = 0;
while( check_c(s[istart]) && (istart < sLength-1) ) istart++;
if (istart == sLength-1){
if (! check_c(s[istart])) vstr += s[istart];
return vstr;
}
// }
iend = istart+1;
while ( (! check_c(s[iend])) && (iend < sLength-1) ) iend++;
if (check_c(s[iend])) iend--;
for (int i = istart; i <= iend; i++)
vstr += s[i];
return vstr;
}
if (ipos > 0){
int istart = 0;
for (int i = 0; i < ipos; i++){
while( check_c(s[istart]) && (istart < sLength-1) ) istart++;
if (istart == sLength-1) return "";
int iend = istart;
while ( (! check_c(s[iend])) && (iend < sLength-1) ) iend++;
if (iend == sLength-1) return "";
istart = iend+1;
}
while( check_c(s[istart]) && (istart < sLength-1) ) istart++;
if (istart == sLength-1)
if (! check_c(s[istart])){
vstr = s[istart];
return vstr;
}else{
return "";
}
iend = istart;
while ( (! check_c(s[iend])) && (iend < sLength-1) ) iend++;
if (check_c(s[iend])) iend--;
for (int i = istart; i <= iend; i++)
vstr += s[i];
return vstr;
}
return vstr;
}
//
// nmに読み込み用テキストファイル名を設定
// オープンに成功すればiCondの値は0が設定される。
//
RdTxtLn::RdTxtLn( string nm ): iCond(0){
fin = fopen( nm.c_str(), "r" );
if (fin == NULL) {
iCond = 9;
return;
} else {
iCond = 0;
return;
}
}
RdTxtLn::~RdTxtLn(){
if (iCond == 0) fclose(fin);
}
void RdTxtLn::open( string nm ){
fin = fopen( nm.c_str(), "r" );
if (fin == NULL) {
iCond = 9;
return;
} else {
iCond = 0;
return;
}
}
void RdTxtLn::close(){
if (iCond == 0){
fclose(fin);
iCond = -1;
}
}
//
// メソッドreadlineを1回呼び出すと
// ファイルから1行分がstrに読み込まれる
//
int RdTxtLn::readline( string & str ){
int v = 0;
if (iCond != 0){
v = 1;
return v;
}
const int maxN = 1000;
char c[maxN];
int ipos = 0;
int cv;
while (true){
cv = fgetc(fin);
if (cv == EOF){
c[ipos] = 0;
str = "";
if (ipos > 0)
for (int i = 0; i < ipos; i++)
str += c[i];
iCond = 1;
return v;
}
switch (char(cv)){
case '\r': break;
case '\n': c[ipos] = 0; ipos *= -1; break;
default : c[ipos] = char(cv);
ipos++;
if (ipos > (maxN-2)){
c[maxN-1] = 0;
v = 9;
return v;
}
break;
}
if (ipos <= 0) {
ipos *= -1;
str = "";
if (ipos > 0)
for (int i = 0; i < ipos; i++)
str += c[i];
v = 0;
return 0;
}
}
}
} // mylib
================================