右の画像ファイルの16進ダンプ内容を、以下に示します。
ファイル名は『red128.gif』です。
C言語では、1byteの入力関数用として、fgetc関数が標準関数として用意されています。
この関数は、FILE *型の入力ストリームを引数にして、それから入力した1byteを返します。
ただしエラー時は、-1のEOFを返します。
つまり、fgetc引数にfopenでオープンしたポインタ(FILE *型)を指定すると
ファイル操作ができます。
上記画像ファイルの『red128.gif』をオープンして、
そのデータの先頭から各バイトを順次に16進数で画面に表示するプログラムを以下に示します。
#include <stdio.h>
main(int argc, char *argv[])
{
char *p_file; /* ファイル名管理用*/
FILE *fpr; /* 読み取りストリーム管理用FILE Pointer by Read */
int pos = 0; /* ファイル内位置管理用(position )*/
int c; /* fgetの戻り値記憶用*/
p_file = argv[1]; /* コマンドラインパラメタより、ファイル名を設定 */
fpr=fopen( p_file , "r" );/* ファイル読み取りモードでオープン*/
/* ファイルからの読み取り繰り返し*/
while( (c=fgetc(fpr)) != EOF ){
if(pos % 16 == 0){
printf("\n%04X ", pos);
}
printf("%02X ", c);/* 表示 */
pos++;
}
fclose(fpr); /* ファイルクローズ*/
}
このプログラムの実行結果は、次のようになります。
これは、ファイルの読み取りが途中で終了するからです。
上記の"r"をクリックして、"rb"へ変更することで、
最後まで正しく読み込めるプログラムになります。
これは、fopenの第2引数の指定によりテキストモード("r")とバイナリモード("rb")のアクセス方法があり、
それによりfgetcやfputcなどの挙動が変るためです。
(これは、Windowsシステムの特有の区別で、unix関連は全てバイナリモードで、区別していません。)
バイナリモード時は、unix と同じで全ての1byeを単純に入出力します。
対して、
テキストモードの場合は次のように変ります。
'\n' つまり、0xA0 のLFコード(line feed)の1byteを、fputc ('\n' ,fpr)などで出力すると、
0x0D 0x0Aの2byteが出力されます。(0x0DはCR: Carriage Returnです)
fgetc(fpr)などの入力は、0x0D 0x0Aの2byteを読み込むことでリターンし、
その時の戻り値が、'\n' つまり、0xA0の1byteになります。
つまり、改行に関連するコードだけ、メモリ1byteが2byteに変換して出力され、入力時は、0x0D 0x0Aの2byteが1byteの'\n'に変換されて入力されるわけです。
またテキストモードでは、テキストファイルの終端に使われるEOFのコード0x1Aを読み取ると、
ファイル終端と判断してfgetcの戻り値がEOF定義の-1になってしまいます。
よって、画像ファイルのようにバイナリファイルで、0x1Aを含むデータがあるファイルに対して、
前の実行例のように テキストモード("r")でfopenすると、
読み取りの中断が起きてしまいます。
モード | ファイルがあるときの動作 | ファイルがないときの動作 |
---|---|---|
"r"または"rb" | 読み出し専用ストリームポインタを返す | エラーでNULLを返す |
"w"または"wb" | 書き込み専用ストリームポインタを返す。 既存のファイルサイズを 0 にする | 新規に作成し、それへの書き込み専用ストリームポインタを返す。 |
"a"または"ab" | 追加書き込み専用ストリームポインタを返す。ファイル最後に追加します | 新規作成 |
"r+"または"rb+" | 読み込みと書き込み | エラーでNULLを返す |
"w+"または"wb+" | 書き込みと読み込み 既存のファイルサイズを 0 にする | 新規作成 |
"a+"または"ab+" | 読み込みと追加書き込み 最後に追加する | 新規作成 |