Version 5.15
API でファイル操作
「というわけで、今回は API を使って読み込んでみます」
『 iostream にランタイムに MFC 、とどめに API ね』
「ただ、かなりややこしいから覚悟するように」
『げげ』
「まず、この前の MFC の例みたいに、 CFileTestDlg::OnBtnShow() の最初
の部分にプログラムを書いて、 return で終了させて、そのあとに iostream
のプログラムを取っておく形にします」
『 MFC のは削除しちゃうのね』
「そういうこと。で、次のようなプログラムを書き込んで」
void CFileTestDlg::OnBtnShow()
{
// ファイルを開きます。
HANDLE hFile
= CreateFile
( "Data.txt", GENERIC_READ, 0, NULL
, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if( hFile == INVALID_HANDLE_VALUE )
{
TRACE( "ファイルがない!\n" );
return;
}
char chAllLine[1024];
if( 1024 < GetFileSize( hFile, NULL ) )
{
TRACE( "ファイルが大きすぎます!\n" );
CloseHandle( hFile );
return;
}
DWORD dwReadedSize;
BOOL bRes
= ReadFile
( hFile, chAllLine, 1023
, &dwReadedSize, NULL );
if( bRes == 0 && dwReadedSize == 0 )
{
TRACE( "ファイルから読みとれませんでした。\n" );
CloseHandle( hFile );
return;
}
std::istrstream cStrStrm( chAllLine, dwReadedSize );
while( !cStrStrm.eof() )
{
int i;
cStrStrm
>> i;
if( cStrStrm.fail() )
{
TRACE( "整数値じゃないです\n" );
CloseHandle( hFile );
return;
}
char chDest[256];
sprintf( chDest, "%d", i );
m_cDataLstBox.AddString( chDest );
}
CloseHandle( hFile );
return;
// 以下、 iostream のプログラムを取っておきましょう。
『な、なが〜い!!』
「ホント、長いよねぇ。僕も普段は API でファイル操作ってしないから、
もう少し簡単にする方法があるのかなーとは思うんだけど、これが限界」
『なさけなー』
「でも、プログラムが部分部分の集まりなのは同じ。というわけで少しずつ
見ていきましょう」
// ファイルを開きます。
HANDLE hFile
= CreateFile
( "Data.txt", GENERIC_READ, 0, NULL
, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if( hFile == INVALID_HANDLE_VALUE )
{
TRACE( "ファイルがない!\n" );
return;
}
『あ、いつものファイル開くとこでしょ。でも CreateFile() って、ファイ
ル作ってるの?』
「ううん、 CreateFile() って API はファイルを作ることだけじゃなくて
開くこともできるから。意味的には〈ファイルを操作するためのものを作る〉
って考えた方がいいかも」
『なんか複雑』
「 CreateFile の次の2行が引数」
『ひとつめは開くファイル名でしょ、ふたつめは CFile::modeRead とかと
同じフラグだよね』
「そう、その辺も MSDN の CreateFile() のリファレンスに書いてあるから」
『え〜? ぱっと読んだけどむっちゃ難しかったよ!?』
「あれは確かにね……。ま、ここで大まかに憶えて、リファレンスでフラグ
や引数の意味を調べる、くらいに使った方がいいかな」
『うんそうするー。みっつめは……共有?』
「このファイルを開いている間、他のアプリがこのファイルを開けないよう
にすることができるから。そういうのを指定するフラグをここに渡します」
『今回はそゆことしないから 0 ね。次の子プロセスって?』
「これは難しいからパス」
『だから NULL を渡すっと。2行目の OPEN_EXISTING はフラグっぽいね』
「この引数はファイルがなかったときにどうするかを決めるフラグ。この
OPEN_EXISTING は〈ファイルが存在しなかったらエラー〉にするフラグ」
『 CREATE_NEW だと新しく作る、そっか、こっちなら〈ファイルを作る〉に
なるんだね。 FILE_ATTRIBUTE_NORMAL もフラグだね』
「こっちはファイルの状態。隠しファイルかとか読み取り専用かとか、ファ
イルをフォルダで右クリックして出るメニューの〈プロパティ〉のだね」
『あー、あれか。 FILE_ATTRIBUTE_NORMAL は普通のファイルってことね』
「最後も難しいからパス」
『だから NULL 。この〈難しい〉ってどんな感じに難しいの?』
「この辺のは〈ウィンドウズの機能〉に深く関わってる部分だから。ウィン
ドウズシステムを理解するのは難しいからね」
『そーゆーもんなんだ』
「引数は以上。戻り値は HANDLE 型」
『何この型は。あ、ハンドルって言ったらウィンドウハンドルとかそういう
のあったよね』
「それと同じ。さっき〈ファイルを操作するためのものを作る〉って言った
でしょ。これを操作するためのハンドルが返ってくるって考えればいいかな」
『でもさ、普通 HFILE 型とかじゃない?』
「それがないんだよね。リファレンス見れば分かるけど、 CreateFile() は
ファイル以外のも開けるから、そのために HANDLE 型っていうあいまいな型
を使ってるんだよね」
『……それってヤバくない?』
「かなりまずいよね。 API って OS やハードウェア寄りの細かい操作がで
きるように設計されてるからこうなってるんだけど、その分使い方を誤ると
まずいことになるね」
『はー、なんか怖いね』
「正直な話、今ここで API でファイル操作する方法教えてるけど、もっと
C++ 言語を憶えるまでは API でしないほうがいいかもね」
『それはそうねー、使い方とか間違えてたら怖いもん』
「ま、そうは言っても壊すくらい無茶しないと分からないこともあるけどね」
『無茶したことあるんだ』
「まーね。で、話を戻すとこの戻り値 HANDLE 型を使って、これからファイ
ルを操作していきます。そういうのあったよね」
『ランタイム使ったときのファイルポインタ! あれも fopen() の戻り値
だったよね』
「そう同じ。で、ファイルを開くのに失敗してたら INVALID_HANDLE_VALUE
って値が返ってくるから」
『それを if でチェックね』
「この辺もランタイムと同じだね。そうそう、同じって言ったら、最初のプ
ログラムの最後の方にこの行があるでしょ」
CloseHandle( hFile );
『 fclose() と同じ?』
「そういうこと。 API も関数だから、わざわざこういうふうにファイルを
閉じなきゃダメ」
『クラスならそういうことしなくていいんだよね』
「クラスには〈自動的に関数を呼びだしてくれる機能〉があるから、その関
数の中で閉じればいいからね」
『……んーと、質問!』
「はい火美ちゃん」
『ぶっちゃけた話、なんで API だとこんなめんどいの?』
「さっきもちょっと触れたけど、 API は OS やハードウェアの機能を使え
るようになってて、その細かい機能を使うために引数がいっぱいあるわけ」
『ってことは、 iostream やランタイムとか MFC じゃ、そういうの使えな
いってこと?』
「そういうこと。 iostream は〈標準 C++ ライブラリ〉、ランタイムは
〈標準 C ライブラリ〉って呼ばれるものの一部。標準だから、他の開発環
境や OS でも使われます」
『そういうのに OS の操作する機能付けても、実際に OS が対応してないか
もしんないってわけ?』
「それが標準ライブラリのスタンスってことだね。汎用的に使えるようにし
たいから、細かい機能はなし、ってこと」
『その細かい機能って具体的にゆーと?』
「たとえばさっき言った〈隠しファイル〉とか〈読み取り専用〉とかのプロ
パティ。 OS によってはああいう設定がファイルにはないからね」
『ふ〜ん。ふたつめの質問!』
「はい火美ちゃん」
『水希ちゃんが書いたプログラム、なんで = や ( や , が最初に来るよう
にしてるの?』
「あー、あれはね」
HANDLE hFile =
CreateFile( "Data.txt", GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
「ってなってたら〈前の行から続いてる〉って分からないでしょ。プログラ
ムはどの行も左から読み進めるから、まず = や , が出てきたら前の行から
の続きだなって分かるように」
『インデントがあるじゃん』
「インデントは信用しないっていうのが僕のスタンス」
『こだわりってことねー』
「……別に真似しなくたっていいよ、他に誰もしてないから」
『んー、考えとく。改行やたらと多いのは?』
「これはただの見やすさかな。引数の部分だけまとめたいとか、横に長いよ
りも縦に長い方が読みやすいとか」
『それはよく分かんない……』
/*
Preview Next Story!
*/
『でもホント、 API って面倒ね』
「ファイル操作は iostream とかあるからまだいい方だけど」
『ってことは、 API しか方法がないっていうのも多いの?』
「いーっぱいあるよ」
『げげ』
「というわけで次回」
< Version 5.16 API で読み取る! >
『につづく!』
「ま、 iostream も〈他の人が作ってくれた〉ってだけだけど」
『 API だけのも誰かが作ってくれればいいわけだ』
「コンピューターが自動的に作ってくれると楽なんだけどね〜」
『……なんであたし見るのよ』