2012年03月26日

[C++]fwriteでバイナリデータを書き込んだり、挿入したり。

前回はC言語(C++)でバイナリデータを読み込む方法を紹介したが、今回はバイナリデータの書き込む方法と、プラスアルファとしてデータを挿入するテクニックを紹介したいと思う。

まずは以下のサンプルソースを見て欲しい。

fwrite.c
#include <stdio.h>
#include <stdlib.h>

int main(){
FILE* fp;
size_t num;
char* fname = "./fwrite.dat";

// ==================================
// ■データ書込み
// ファイルに "apple\0" と書き込み、
// その後、"Apple\0" と書き換え
// ==================================

// バイナリ書込モードでファイルオープン
if ((fp = fopen(fname, "wb")) == NULL) {
fprintf(stderr, "file open failed! : %s\n", fname);
exit(EXIT_FAILURE);
}

// "apple\0" と書き込み
char d1[6] = "apple\0";
num = fwrite(&d1, sizeof(d1), 1, fp);

/*
この時点で
fwrite.dat の内容は、"apple\0"
*/

// 先頭(0byte目)にカーソル移動
fseek(fp, 0, SEEK_SET);
// "a" を "A" に書き換え、"Apple\0" に
char d2 = 'A';
num = fwrite(&d2, sizeof(d2), 1, fp);

/*
この時点で
fwrite.dat の内容は、"Apple\0"
*/

// ファイルクローズ
fclose(fp);


// ==================================
// ■データ挿入
// "Apple\0" の5byte目の直後へ
// "t!" を挿入し、"Applet!\0" に。
// 編集結果は別ファイルへ出力する。
// ==================================

// 出力ファイル名
char* output = "./output.dat";

// 読込用ファイルポインタ
FILE* fpr;
// 書込用ファイルポインタ
FILE* fpw;

// バイナリ読込モードでファイルオープン
if ((fpr = fopen(fname, "rb")) == NULL) {
fprintf(stderr, "read file open failed! : %s\n", fname);
exit(EXIT_FAILURE);
}
// バイナリ書込モードでファイルオープン
if ((fpw = fopen(output, "wb")) == NULL) {
fprintf(stderr, "write file open failed! : %s\n", fname);
exit(EXIT_FAILURE);
}

// 作業用変数
char tmp;
// 挿入したい文字列
char ins[2] = "t!";

while (1) {
// 読込カーソルが挿入ポイント(5byte目)に来た場合
if (ftell(fpr) == 5) {
// 挿入したい文字列を書込み
fwrite(&ins, sizeof(ins), 1, fpw);
}
// 1byte読込み
if (fread(&tmp, sizeof(tmp), 1, fpr) == 0) {
break;
}
// 1byte書込み
fwrite(&tmp, sizeof(tmp), 1, fpw);
}

/*
この時点で
fwrite.dat の内容は、"Apple\0"
output.dat の内容は、"Applet!\0"
*/

// 読込用ファイルクローズ
fclose(fpr);
// 書込用ファイルクローズ
fclose(fpw);

return EXIT_SUCCESS;
}


"wb"モード(バイナリ書込モード)でファイルを開き、stdio.h の fwrite関数を使ってデータを書き込むというのが基本パターンである。

size_t fwrite(const void* ポインタ, 
size_t 1アイテムのサイズ,
size_t アイテム数,
FILE* ファイルポインタ)


戻り値 size_t は書き込んだアイテム数だ。

すでに書きこまれたデータを途中で変更したい場合は、変更したいアイテムまでカーソルを移動させてfwriteすればよい。

が、ここで一つ注意が必要である。fwriteはデータを「挿入」してくれるわけではないということだ。あくまでも「上書き」なのである。

データ挿入は意外と面倒臭い



例えば上のサンプルソースのように、"Apple\0" というデータに "t!" という文字を挿入して "Applet!\0" に変更したい場合、6バイト目の先頭、つまり "e" の後ろへカーソルを移動させて "t!" を fwrite すればいいのではないかと初心者は直感的に感じてしまうようだが、実際はそれでは期待通りの結果にはならない。何も考えずに "t!" を指定のカーソル位置へ fwrite すると、できあがるデータは "Applet!" であって、期待している "Applet!\0" にはならないということだ。

期待通りの結果を得るためには、少々面倒だが、上記サンプルソースの後半処理のように、(1)読込用ファイルポインタfprと書込用ファイルポインタfpwを二つ用意しておいて、(2)fprから1byte読み込む度にfpwに1byte書き込み、(3)挿入したい地点にカーソルが来た時に、挿入したい文字列 "t!" をfpwに書き込むという条件文を入れる必要があるのだ。

fwrite関数の説明にしてはちょっと横道に逸れてしまった感が否めないが、「データ挿入」処理というのはプログラマが必ず一度は突き当たる壁だと思っているので、ここで敢えて紹介しておいた。

もっとスマートなロジックをご存知の方はコメ欄でツッコミをよろしく。


C++プログラミング入門
グレゴリー サティア ダウグ ブラウン
オライリー・ジャパン
売り上げランキング: 61971

PR:お買い物はAmazonで
posted by 寄り道退屈男 at 18:09 | Comment(0) | TrackBack(0) | C++
この記事へのコメント
コメントを書く
お名前: [必須入力]

メールアドレス: [必須入力]

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
※ブログオーナーが承認したコメントのみ表示されます。
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/54639707
※ブログオーナーが承認したトラックバックのみ表示されます。
※言及リンクのないトラックバックは受信されません。

この記事へのトラックバック