Version 12.12
構造体のファイル読み書き
「前回は、構造体のアライメントとパディングについて説明しました」
『構造体のメンバ変数が 8 バイトずつになっちゃう、それはプロジェクト
の設定で決められる、だよね』
「そう。それを踏まえて、構造体をファイルに書き込む場合について見て
みます」
struct TEST_STRUCT_DOUBLE_2
{
char m_ch;
double m_d;
char m_ch2;
};
void WriteStructToBinaryFile()
{
// ファイルを開きます。
FILE *pstFile
= fopen( "StructBinary.aaa", "wb" );
if( !pstFile )
{
TRACE( "ファイルが開けない!\n" );
return;
}
// 構造体を準備します。
TEST_STRUCT_DOUBLE_2 stTEST_STRUCT_DOUBLE_2;
memset( &stTEST_STRUCT_DOUBLE_2, 0x00, sizeof( stTEST_STRUCT_DOUBLE_2 ) );
stTEST_STRUCT_DOUBLE_2.m_ch = 63;
stTEST_STRUCT_DOUBLE_2.m_d = 2.0;
stTEST_STRUCT_DOUBLE_2.m_ch2 = 63;
// 構造体を書き込みます。
fwrite
( &stTEST_STRUCT_DOUBLE_2
, sizeof( stTEST_STRUCT_DOUBLE_2 )
, 1
, pstFile
);
// ファイルを閉じます。
fclose( pstFile );
return;
}
「構造体は前回と同じ TEST_STRUCT_DOUBLE_2 です」
『 memset() で 0 にして、そのあとそれぞれの変数に入れて……あれ?
この前って memset() に 0xAA セットしてなかったっけ』
「あれはパディングの部分を見るためのテストだから。本当はこうやって
0 を入れるのが普通」
『確かに 0xAA ってちょっと変だもんね……』
「まぁ別に特別な理由はないから 0x00 以外でもいいんだけど、必要性がな
ければ 0x00 の方がいいかな」
『その次はファイルの書き込みね。使ってるランタイムは
Version 12.09 ( No.232 ) と同じね』
「ここで重要なのは、 sizeof( stTEST_STRUCT_DOUBLE_2 ) の部分。前回
言ったように、ここにはパディングの分が入るから」
『見た目より大きなのになるってことだね』
「そういうこと。で、実際に、アライメントを 8 バイトにしてファイルに
書き込むと、次のようなデータになります」
『バイナリーモードで開いて、と』
3F 00 00 00 00 00 00 00
00 00 00 00 00 00 00 40
3F 00 00 00 00 00 00 00
『って、この前構造体の中身を見たときとほとんど同じじゃん。 AA が 00
になったってだけで』
「そう、 memset() で 0xAA じゃなく 0x00 をセットしてるからね。でも、
それが重要」
『どゆこと?』
「構造体の中身がそのまま書き込まれるってことは、アライメントの設定次
第でファイルの構造が変わるってこと」
『あ……アライメントが 0 バイトだと、ファイルもパディングなくなった
状態で書き込まれるんだ』
「実際に試してみて」
『ほい。プロジェクトの設定で変えて、リビルドしてと』
3F 00 00 00 00 00 00 00 40 3F
『見事にパディングなくなっちゃった……』
「こんなふうに、アライメントの設定は実際のファイルの中身についても影
響します。さて、今度はこれを読み込んでみます」
void ReadBinaryFiletoStruct()
{
// ファイルを開きます。
FILE *pstFile
= fopen( "StructBinary.aaa", "rb" );
if( !pstFile )
{
TRACE( "ファイルが開かない!\n" );
return;
}
// 構造体を読み込みます。
TEST_STRUCT_DOUBLE_2 stTEST_STRUCT_DOUBLE_2;
fread
( &stTEST_STRUCT_DOUBLE_2
, sizeof( stTEST_STRUCT_DOUBLE_2 )
, 1
, pstFile
);
TRACE( "%d\n", stTEST_STRUCT_DOUBLE_2.m_ch );
TRACE( "%.20f\n", stTEST_STRUCT_DOUBLE_2.m_d );
TRACE( "%d\n", stTEST_STRUCT_DOUBLE_2.m_ch2 );
// 63
// 2.00000000000000000000
// 63
// ファイルを閉じます。
fclose( pstFile );
return;
}
『ぱっと見いつも通り』
「ランタイムも今までのと同じだから特に問題ないよね」
『うん。ビルドして実行! うん、ちゃんとデータ取れてる!』
「こんなふうに、構造体を使って読み書きをすると、 fread() や fwrite()
を何度も使わずに複数のデータを読み書きできるっていうメリットがありま
す」
『あ、そういえば。 Version 12.10 ( No.233 ) のときはめんどくさかった
もんね』
「でも、実際のところ、構造体を使ってファイルの読み書きをするのはデメ
リットの方が多いかも」
『え、そうなの?』
「まずはさっきのアライメントの問題。今は、書き込むときも読み込む時も
アライメントは 1 バイトにしていました」
『……だから読み込めたけど、もし今、アライメントを 8 バイトにして、
さっきのファイルを開くと……』
「やってみて」
『う、うん……』
63
-925596313489040890000000000000000000000000000000000000(以下略)
-52
『あ”』
「という感じに、まったく開くことができません」
『でも、今の状態でファイルに書き込めば、それは読み込めるんだよね』
「うん、アライメントが 8 バイトで書き込まれるからね。でも……たとえ
ばプログラムがバージョンアップしたときとかに、うっかりアライメントを
変えちゃうと」
『う”、前のが読み込めなくなる』
「それに、アライメントの設定はプロジェクトの設定で変わるから、ソース
ファイルとバイナリーファイルだけ送って、それをビルドして実行すると」
『アライメントが違って読み込めない……』
「っていう場合が多々あります。そのほかにも、構造体で読み書きするのに
はいくつか問題があります」
『たとえば?』
「たとえば、クラスの問題。クラスには、継承の関係とかもあって、単純に
ファイルには書き出せないようになっています」
『そういう複雑な情報ってファイルに出せないの?』
「普通には無理。ところが、 Version 7.07 ( No.127 ) で説明したよう
に」
『そうよ、構造体とクラスってほとんど同じなんじゃない?』
「だから、構造体だからって簡単にファイルに書き込むのはちょっと、って
いうことがあるから」
『やっぱ書き込むのはダメ、ってことね』
「ただ、複数のデータをまとめて書き込めるっていうのは便利だし、以前は
こうやって書き込むのは普通だったから」
『……結局どっちなの!?』
「えーっと……とりあえずは、構造体を直接書き込むのはしない方向で。で
も、仕組みとか方法は憶えておいて」
『その以前の、とかの関係?』
「そういうこと。昔のを使うときにはね。あと、構造体で書き込んでも、読
み込む時には構造体を使わない、っていう方法もあります」
『どゆこと?』
void ReadStructBinaryFile()
{
// ファイルを開きます。
FILE *pstFile
= fopen( "StructBinary.aaa", "rb" );
if( !pstFile )
{
TRACE( "ファイルが開かない!\n" );
return;
}
char ch;
double d;
char ch2;
fread( &ch, sizeof( ch ), 1, pstFile );
fread( &d, sizeof( d ), 1, pstFile );
fread( &ch2, sizeof( ch2 ), 1, pstFile );
TRACE( "%d\n", ch );
TRACE( "%.20f\n", d );
TRACE( "%d\n", ch2 );
// 63
// 2.00000000000000000000
// 63
// ファイルを閉じます。
fclose( pstFile );
return;
}
「あ、 fread() でべたに読み込んでる」
『ただ、これはアライメントが 1 バイトの場合の処理』
「 8 バイトの場合には?」
『ランタイムに fseek() っていうのがあって、これだとファイルポインタ
を自由に移動できるから』
「パディングを飛ばせる?」
『そういうこと』
/*
Preview Next Story!
*/
「バイナリーデータ編は次回で最後です」
『細かいルール多かったね』
「だから次回はそのまとめ」
『というわけで次回』
< Version 12.13 バイナリーのまとめ >
「につづく!」
『お、今回は全13回!』
「というか、文字列編が長すぎたね……」