バイナリデータ


数値を入出力する

以前ファイル操作の基本を覚えました
fprintf()やfscanf()関数で文字データを操作することができました

しかし、以前扱った関数は整数型には不向きです
なぜならば、fprintf()関数などはバイナリデータを文字データに変換するからです
詳細はASCIIコードを学習すればわかりますが、その意味はまったく違うものになっています

ここではバイナリデータのファイルへの入出力を試みてみましょう
バイナリデータと文字データの変換に対して、通常は意識する必要はありません
しかし、その変換作業がアプリケーションの実行速度に深刻な問題を起こす場合など
直接バイナリデータを扱う必要がでてくるケースもあります

たとえば、次のようなプログラムの場合の問題点を考えましょう
#include <stdio.h>
#include <stdlib.h>

int main() {
        int i;
        FILE *fp;
        printf("値を入力してください");
        scanf("%d" , &i);

        if ((fp = fopen("test.txt" , "w")) == NULL) {
                fprintf(stderr , "ファイル操作中にエラーが発生");
                exit(1);
        }

        fprintf(fp , "%d" , i);
        fclose(fp);

        return 0;
}
この場合は、バイナリではなくiの数値がASCIIコードに変換されて出力されます
65 ならば "65" と同じ意味になるということです
もちろんそれが目的ならば問題はありませんが、算術用として一時保存する場合は困ります

方法としてはfputc()やfgetc()を使うのもひとつの方法です
ですが、バイナリデータ専用としてより適した関数が用意されています
それがfwrite()関数です

size_t fwrite(void *バッファ , size_t サイズ , size_t カウント , FILE *ストリーム);

この関数はバッファからサイズ分のデータをカウント回ストリームに出力します
戻り値は、実際に書き込んだ回数を返します
void*型やsize_t型については、すでに説明しました
#include <stdio.h>
#include <stdlib.h>

int main() {
        char i[] = { 65 , 66 , 67 , 68 , 69 , 70 };

        fwrite(&i , sizeof(char) , 6 , stdout);
        printf("\n");
        fwrite(&i , sizeof(char)+1 , 3 ,stdout);

        return 0;
}
このプログラムでは、fwrite()を使って配列のバイナリデータを標準出力に出力しています
標準出力やテキストエディタなどに出力すると、バイナリデータがASCIIコードになって確認できます

ABCDEF
ABCDEF

このような結果になったはずです
65はASCIIコードでAです
ここで、65と表示されずAと表示されたということは、データがバイナリデータで扱われたということです

fwrite()関数を二回使っていますが、やっている内容は同じです
1バイトを6回分まで出力するか、2バイトを3回分まで出力するかです
出力される合計バイト数は同じですね

しかし、このプログラムのchar型変数iの型をint型に変更してみると上の結果は得られません
バイナリデータでは、上位ビットが無視されないので
6バイトまでの出力ならば i[0] と i[1] の途中(上位2バイト)までしか出力されません(intが4バイトの場合)

次に、同様の方法でバイナリデータを読み込む方法を覚えましょう
バイナリデータをそのまま読み込むにはfread()関数を使用します

size_t fread(void *バッファ , size_t サイズ , size_t カウント , FILE *ストリーム);

引数や戻り値の内容はfwrite()とまったく同じです
ストリームからサイズ分をカウント個バッファに読み込みます
#include <stdio.h>
#include <stdlib.h>

int main() {
	int i[] = { 100 , 200 , 300 } , re[3];
	FILE *fp;

	if ((fp = fopen("test.txt" , "w")) == NULL) {
		printf("ファイル操作中にエラーが発生");
		exit(1);
	}

	fwrite(i , sizeof(int) , 3 , fp);
	fclose(fp);

	if ((fp = fopen("test.txt" , "r")) == NULL) {
		printf("ファイル操作中にエラーが発生");
		exit(1);
	}

	fread(re , sizeof(int) , 3 , fp);
	fclose(fp);	

	printf("%d" , re[0] + re[1] + re[2]);
	return 0;
}
データはバイナリデータとして出力されます
このデータをバイナリデータとして読み込むことによって、そのまま計算式に使えます
作成されたファイルをメモ帳などのテキストエディタで開いても、意味不明な記号にしか見えません
これは、ASCIIコード(文字データ)ではなく、バイナリデータだからです
ASCIIコードとしてデコードしても、その多くは意味のない数列なので、結果として意味不明な記号が出てきます

このプログラムで確認したように、アプリケーションの設定データなど
読み込んで直接計算式に使用したりするデータなどはバイナリとして扱えます
とくに今回紹介した関数は、配列として扱うのに非常に優れています
実用化するには、戻り値を監視するなどして、エラー対策もするのが一般的です


size_t fwrite( const void*buffer, size_t size, size_t count, FILE *stream );

書式化せずにストリームにデータを書き込みます

ヘッダ - stdio.h
buffer - 書き込むデータのバッファを指定します
size - バイト単位で書き込む項目の単位を指定します
count - 書き込まれる項目数を指定します
stream - 出力するFILE構造体へのポインタを指定します

戻り値 - 実際に書き込んだ項目数を返します。エラーの場合はcount未満

size_t fread( void *buffer, size_t size, size_t count, FILE *stream );

書式化せずにストリームからデータを読み込みます

ヘッダ - stdio.h
buffer - 書き込むデータのバッファを指定します
size - バイト単位で書き込む項目の単位を指定します
count - 書き込まれる項目数を指定します
stream - 読みこむFILE構造体へのポインタを指定します

戻り値 - 実際に書き込んだ項目数を返します。エラーの場合はcount未満



前のページへ戻る次のページへ