Version 5.17
iostream で文字列操作!
「まずはごめんなさい」
『うおっ、いきなり謝るか』
「まず、インクルードファイルについて。インクルードファイルって憶えて
る?」
『憶えてるよん、 Ver 5.09 ( No.074 ) でやったよね』
「そう、今の FileTestDlg.cpp の最初で」
#include "stdafx.h"
#include <fstream>
#include "FileTest.h"
#include "FileTestDlg.h"
「ってしたよね」
『こうすれば、 fstream の機能が使えるんだよね。それが std::ifstream
なんだよね』
「で、実はここで新しくインクルードしなきゃいけないファイルがあったん
だけど、それを書き忘れてました」
『情けなー』
「ホントはこうです」
#include "stdafx.h"
#include <fstream>
#include <strstream>
#include "FileTest.h"
#include "FileTestDlg.h"
『 strstream っていうのをインクルードすればいいのね』
「今回紹介する std::istrstream を使うのにこれが必要だから。で、今回
紹介するプログラムにもちょっとミスがあったから」
DWORD dwReadedSize;
BOOL bRes
= ReadFile
( hFile, chAllLine, 1023
, &dwReadedSize, NULL );
if( bRes == 0 && dwReadedSize == 0 )
{
TRACE( "ファイルから読みとれませんでした。\n" );
CloseHandle( hFile );
return;
}
// ここまでは前回に解説しました。間違いもない……はず。
CloseHandle( hFile );
std::istrstream cStrStrm( chAllLine, dwReadedSize );
while( !cStrStrm.eof() )
{
int i;
cStrStrm
>> i;
if( cStrStrm.fail() )
{
TRACE( "整数値じゃないです\n" );
return;
}
char chDest[256];
sprintf( chDest, "%d", i );
m_cDataLstBox.AddString( chDest );
}
return;
// 以下、 iostream のプログラムを取っておきましょう。
『 Ver 5.15 ( No.080 ) と見比べると、 CloseHandle( hFile ) 呼ぶ位置
が違うだけ?』
「そう。 CloseHandle( hFile ) の機能は?」
『 CreateFile() で開いたファイルを閉じるの』
「今回紹介するところはもうファイルの操作しなくていいから、その前に
ファイルを閉じちゃって良かったんだよね」
『つまりそれに気付かなかったと』
「 API は使い慣れてないからな〜。では今回の解説に入りましょう」
『ってゆーか、 Ver 5.10 ( No.075 ) の std::ifstream 使ったのとほとん
ど同じだよね』
「あ、そういえば i を宣言してる場所がばらばらだな〜。まぁこれは今度
解説しよう。そう、 std::ifstream とほとんど同じ」
『違いは?』
「 std::ifstream はファイルから読み取るためのクラスだったけど、
std::istrstream は文字配列から読み取るためのクラス」
『 API 使う例だからって、なんかこういう使い方って変くない?』
「ま、統一されてないのは変だけどね。でもこういう柔軟な使い方できるの
は重要だよ。関数やクラスは〈道具〉として使いこなせなきゃいけないから
ね」
『まーそれはそうだけど』
「さて、まず std::istrstream 型の変数を作ります」
『あれ、でもなんか書き方ちょっと違うね。変数作ってるのに、なんか関数
呼んでる見たい』
「これはコンストラクタっていう、クラスが使える機能のひとつ。クラスは
こんなふうに〈変数を作るときに関数を呼び出す〉ことができるんです」
『変数を作るときに関数を呼びだすぅ!? はー、器用なことができるの
ねー』
「でも感覚的には int i = 0; みたくするのと同じ」
『よーするに初期化ね』
「そういうこと。ま、今はこういう使い方ができるくらいでいいから。ちな
みに、これは〈変数を作るとき〉に呼び出される関数だけど、〈変数がなく
なるとき〉に呼ばれる関数もあります」
『あーっ、勝手にファイル閉じてくれるってヤツだ!』
「そう、ファイルを閉じたりする後処理をしてくれるのが、デストラクタっ
ていう、変数がなくなるときに呼ばれる関数」
『なんかクラスって便利。だからランタイムや API とかよりも iostream
や MFC 使った方が楽なのね』
「そういうことになるかな。ま、今は使う段階だから楽だけど、作る段階に
なったら」
『大変なのね……』
「で、 cStrStrm を作るときにコンストラクタを呼び出して cStrStrm の中
身を初期化します」
『第1引数の chAllLine はファイル全体が入ってる文字配列よね。これが
ファイルの代わりになるんだ』
「 dwReadedSize は ReadFile() から受け取った〈実際に読み取った文字列
のサイズ〉。ってことは?」
『ってことは、 chAllLine の中に入ってる文字列のサイズってことね』
「この第2引数で cStrStrm のサイズを指定します。こうすればこれ以上は
み出ないから」
『こーゆーことしなきゃいけないんだ』
「はみ出てるかどうかは次の std::istrstream::eof() で分かります」
『ってゆーか、こっから先は std::ifstream とまったくって言っていいほ
ど同じよね』
「 iostream のメリットはそこだね。同じ系統のクラスなら同じ使い方でい
いっていうのが分かりやすいでしょ」
『まーこれだけ見れば分かりやすいかなー』
「またそーゆーこと言う。さて、ここまでで iostream 、ランタイム、 MFC
そして API でファイル処理をしてきたわけだけど、どう?」
『ってゆーかさ、ファイル操作そのものってどれも同じじゃん、開いて読み
込んでそして閉じるってゆー』
「うんうん」
『それよりも文字列操作の方がめんどかった』
「うん、僕も面倒だった」
『はぁ?』
「 iostream には〈書式化機能〉、つまり整数値や文字列への変換機能も付
いてるわけでしょ」
『そうそう、でもランタイムと MFC は1行ずつ読み込んで整数値に変えてっ
てめんどくさくて、 API なんてファイル全体を読み込むハメに……』
「どうしてもローレベルのライブラリほど、便利な機能が省かれてる傾向に
あるからね」
『ローレベルって低レベルってこと?』
「いや、そういう意味じゃなくて、低層レベルって言った方がいいのかな、
前に〈 API は OS やハードウェア寄りのライブラリ〉って言ったでしょ」
『言ってた言ってた。そういう意味での低層?』
「そう、細かい部分を操作できる意味でね。 iostream はいろんな機能が付
いているぶん、そういう細かいことはできないんだよね」
『やっぱ便利よねー』
「しかーし!!」
『しかぁし?』
「 iostream も MFC も、 ランタイムだって〈低層に高層が重なっている〉
のには変わらないんだよね」
『どゆこと?』
「では、 CFileTestDlg::OnBtnShow() を元に戻しましょう」
void CFileTestDlg::OnBtnShow()
{
int i;
std::ifstream cIFStrm;
cIFStrm.open( "Data.txt" ); // ここにブレークポイント
if( cIFStrm.fail() )
{
TRACE( "ファイルがない!\n" );
return;
}
while( !cIFStrm.eof() )
{
cIFStrm
>> i;
if( cIFStrm.fail() )
{
TRACE( "整数値じゃないです\n" );
return;
}
char chDest[256];
sprintf( chDest, "%d", i );
m_cDataLstBox.AddString( chDest );
}
}
『あ、元の std::ifstream 使ったのだ』
「〈ここにブレークポイント〉ってとこにブレークポイント設置して」
『クリックして手のひらマーク押して実行して【参照】ボタン! 止まった
よ、メモリ見るの?』
「ううん、今回は std::ifstream::open() の中に入ってみます」
『へ?』
「ステップイン……っと、【中カッコに入る】ボタン押して」
『それステップインっつーのね。ほい入った。あ、 Fstream ってファイル
の中みたい』
「そのファイルインクルードしたでしょ」
『あ、そういえば』
「このファイルに std::ifstream::open() の中身があるってことだね。さ
らに入って」
『ほいっと。ん? 同じファイルの違う場所かな』
「ステップイン2回して」
『ほいほい、 Fiopen ってファイルに来たね』
「ステップイン4回でストップ」
『ほいほいほいほい、ってなんも変わんないけど』
「その行って」
if (valid[n] == 0 || (fp = fopen(name, mods[n])) == 0)
「ってなってない?」
『うんなってる……あれ、もしかしてこの fopen() って……』
「というわけで続く!」
/*
Preview Next Story!
*/
『 iostream の中にランタイム!?』
「こういうふうに、ライブラリの中には驚きがいっぱい」
『って、なんか水希ちゃんアヤシイ感じ』
「あ、怪しい!?」
『アヤシイアヤシイ!!』
「というわけで次回」
< Version 5.18 すべての道は API に通ず! >
『につづく!』
「でもなんかドキドキしてるでしょ」
『うん、なんか冒険してる感じ』
「ふっふっふー」
『……ヤな目ぇ』