http://www.cfme.chiba-u.jp/~yama//
C 言 語 におけるファイル 入 出 力 テキスト バイナリの 取 り 扱 い
( )..[4]% gcc Wall o hoge hoge.c..[5]%./hoge 1 : 1 2 : 2 3 : 3 4 : 0 6..[6]%
(! )..[4]% gcc Wall o hoge hoge.c..[5]%!g gcc Wall o hoge hoge.c..[6]%!! gcc Wall o hoge hoge.c..[7]%!../hoge 1 :!g g!!!..!ls!gcc
cp : cp. cp hoge.c hoge2.c hoge.c hoge2.c cp hoge.c jikken1/hoge3.c hoge.c jikken1 hoge3.c mv : ( ) mv. mv hoge.c jikken1/hoge2.c hoge.c jikken1 hoge2.c hoge.c cat : cat cat more. cat hoge.c more hoge.c Return (Enter) 1 q
( ) ( ) C
C ( ) Q1 A1 fopen Q2 A2 Q3 A3 Q4 A4 fclose
#include <stdio.h> #include <stdlib.h> int main(void) { int i, dat, sum = 0; FILE *fp /* exit */ if ( ( fp = fopen( indata.dat, r ) ) == NULL ) { } /* */ printf( n ); exit(1); for (i = 1 ; ; i++){ fscanf(fp, %d, &dat); /* */ if(dat == 0) /* 0 */ break; sum += dat; /* */ } printf( %d n, sum); /* */ } fclose(fp); return(0); /* */
FILE *fp if ( ( fp = fopen( indata.dat, r ) ) == NULL ); /* */ { printf( n ); exit(1); } FILE *fp; C FILE FILE FILE stdio.h stdio.h
FILE *fp; a b /* fp */ FILE *fp; c d e
FILE *fp if ( ( fp = fopen( indata.dat, r ) ) == NULL ); /* */ { printf( n ); exit(1); } fp = fopen(, )
r w a rb wb ab b UNIX Windows C html C
fp = fopen(, ); a b /* b */ fp = fopen( b, r ) ; b b c d e
fp a b c d e f g h i j k l m n o p q r s t u v w x y z k o n o m o j i r e t s u n o n a r a b i n i h a i m i h a a r i m a s e n 2 1
fclose(fp); /* */ fclose (fp);
fclose( fp ) ; a b /* b fp */ fclose(fp) ; c b d e
b d FILE *fp1; FILE *fp2; fp1 = fopen( b, r ); fp2 = fopen( d, w ); fclose( fp2 ); fclose( fp1 ); fp1 b a d fp2 d c b e
FILE *fp if ( ( fp = fopen(, ) ) == NULL ); /* */ { printf( n ); exit(1); } fclose (fp) /* */
fgetc / fputc fgets / fputs fscanf / fprintf fread / fwrite
fgetc / fputc getchar putchar c = fgetc(fp); 8 ( End of File ) c int fputc(c, fp)
C 1 a a b c d e f g h i j k l m n o p q r s b 2 c 3 4 EOF unsigned char int fgetc
mule rsample.txt cat #include <stdio.h> #include <stdlib.h> int main(void) { FILE *fpr; FILE *fpw; int c; /* */ if ( ( fpr = fopen( rsample.txt, r ) ) == NULL ) { return(0); printf( n } ); } exit(1); /* */ if ( ( fpw = fopen( wsample.txt, w ) ) == NULL ) { printf( n ); exit(1); } /* */ while (( c = fgetc(fpr) )!= EOF) { fputc( c, fpw ); } /* */ fclose(fpw); /* */ fclose(fpr);
fgets / fputs gets puts fgets( buf,,fp); NULL buf char fputs(buf, fp)
buf 1 a b c d e a b c d e n 0 f g h i j k l m n o p q r s t null null 2 f g h i j k l m n n 3 o p q r s t 0 0 null
#include <stdio.h> #include <stdlib.h> #define MAX_STRINGS 50 int main(void) { FILE *fpr; FILE *fpw; int c; char data[max_strings]; return(0); /* */ } if ( ( fpr = fopen( rsample.txt, r ) ) == NULL ) { printf( n ); exit(1); } /* */ if ( ( fpw = fopen( wsample.txt, w ) ) == NULL ) { printf( n ); exit(1); } /* */ while ( fgets( data, MAX_STRINGS, fpr )!= NULL) { fputs( data, fpw ); } /* */ fclose(fpw); /* */ fclose(fpr);
fscanf / fprintf scanf printf fscanf (fp,, ); fprintf (fp,, ); scanf / printf
バイナリ 形 式 バイナリー(Binary)とは 0 と 1 の2 種 類 の 数 字 で 表 現 する2 進 数 の 意 味 2 進 数 で 表 されたデータ (バイナリー データ)や 実 行 形 式 のプログラム(バイナリー コード)を バイナリー 形 式 と 言 う 計 算 機 で 扱 うデータは テキスト 形 式 でなければ バイナリー 形 式 である
バイナリ 形 式 の 長 所 短 所 長 所 : - 保 存 するデータに 制 約 がない - 多 彩 な 表 現 の 情 報 を 保 存 交 換 することが 可 能 ( 任 意 のヘッダ 情 報 を 付 加 することができる ) 短 所 : - ファイルフォーマットが 分 からないと 内 容 を 読 む ことができない - 互 換 性 に 劣 る( テキスト 形 式 に 比 較 して )
バイナリデータとは ( 8 bitの 例 ) 10 進 数 : 人 が 理 解 しやすい 16 進 数 : 計 算 機 が 考 えやすい 0 8 84 4 9 73 60 16 56 70 47 33 63 11 1 57 25 14 65 96 86 59 89 87 255 00 08 54 04 09 49 3C 10 38 46 2F 21 3F 0B 01 39 19 0E 41 60 56 3B 59 57 FF 2 進 数 : 実 際 のメモリ 内 容 8 bit = 1 byte 00000000 00001000 01010100 00000100 00001001 01001001 00111100 00010000 00111000 01000110 00101111 00100001 00111111 00001011 00000001 00111001 00011001 00001110 01000001 01100000 01010110 00111011 01011001 01010111 11111111 2 進 数 を 示 す 箱 が 8 個 (8 桁 分 )ある 0 ~ 255を 表 現 できる
バイナリデータとは ( 8 bitの 例 ) 10 進 数 16 進 数 73 60 4 9 3 C 0x49 = 4 16 1 +9 16 0 =73 2 進 数 下 位 のデータ 上 位 のデータ 0 1 0 0 1 0 0 1 0 0 1 1 1 1 0 0 最 上 位 のデータ 最 下 位 のデータ 01001001 = 0 2 7 +1 2 6 +0 2 5 +0 2 4 +1 2 3 +0 2 2 +0 2 1 +1 2 0 =73 = 0x ( 0 2 3 +1 2 2 +0 2 1 +0 2 0 ), 0x ( 1 2 3 +0 2 2 +0 2 1 +1 2 0 ) =0x 49
fread/ fwrite 関 数 fread( buf, サイズ, カウント, fp); 引 数 に 指 定 したファイルポインタの 初 期 位 置 から サイズ( byte 単 位 ) 毎 にカウント( 最 大 値 )まで データを 読 み 込 む 実 際 に 読 み 込 まれたデータの 数 を 返 す 例. size = fread( buf, sizeof(long), 100, fp); intやlongなど, 計 算 機 環 境 によってサイズ( byte 数 )が 異 なることがあるため,sizeof 演 算 子 でデータ 型 の 大 きさ (バイト 単 位 )を 計 算 するのがよい fwrite( buf, サイズ, カウント, fp); 引 数 に 指 定 したファイルポインタの 初 期 位 置 から サイズ 毎 にカウントまでデータを 書 き 込 む
本 日 の 課 題
課 題 : BMPファイルの 入 出 力 24 bit ( 1677 万 色 )のWindows Bitmap 形 式 で 保 存 された 画 像 ファイル bmpsample.bmp を 読 み 込 み, Red,Blue,Greenのいづれかの 色 情 報 のみを 残 し て 他 の 色 情 報 を 排 除 した 画 像 を 作 成 しなさい bmpsample.bmpの 画 像 サイズ( 縦 横 の 大 きさ ) はヘッダ 情 報 を 読 み 込 むことで 認 識 しなさい 作 成 するファイルは 縦 横 の 画 素 数 および 色 数 が 元 画 像 と 同 じままのWindows Bitmap 形 式 とする
元 の 画 像 Redだけ Blue+Green Green だけ2 倍
参 考 資 料 Bitmap 形 式 について
BMPファイル 全 体 の 構 造 BMP フォーマットはヘッダの 種 類 によって Windows Bitmap と OS/2 Bitmap の2 種 類 に 分 けられる これらの2つのフォーマットは,ヘッダのサイズが 異 なっている BMP ファイル 全 体 の 構 造 ファイルヘッダ 情 報 ヘッダ BITMAPFILEHEADER (14byte) BITMAPINFOHEADER (Windows) または BITMAPCOREHEADER (OS/2) + カラーパレット(1, 4, 8 bit の 場 合 必 要 ) 画 像 データ カラーパレーットがない 場 合 各 画 素 に 割 り 振 られた 値 は そのまま 色 (または 明 るさ)を 示 す カラーパレットがある 場 合 は 各 画 素 の 値 はパレットを 参 照 するための 値 であり 色 (または 明 るさ)はパレットで 定 義 されたものとなる
ファイルヘッダ [BITMAPFILEHEADER] 最 初 に 14 byte 固 定 のファイルヘッダ 部 分 がある 最 初 の 2 byte が BM かどうかで ビットマップファイルが 識 別 される bftype bfsize bfreserved1 bfreserved2 bfoffbits 2 byte 4 byte 2 byte 2 byte 4 byte BITMAPFILEHEADER ファイルタイプ ファイルサイズ (byte) 'BM' - OS/2, Windows Bitmap 予 約 領 域 常 に 0 予 約 領 域 常 に 0 ファイル 先 頭 から 画 像 データま でのオフセット (byte)
情 報 ヘッダ < Windows > [BITMAPINFOHEADER] BITMAPINFOHEADER (1) bisize 4 byte 情 報 ヘッダのサイズ (byte) 40 byte biwidth 4 byte 画 像 の 幅 (ピクセル) biheight 4 byte 画 像 の 高 さ (ピクセル) biheight の 値 が 正 数 なら, 画 像 データは 下 から 上 へ biheight の 値 が 負 数 なら, 画 像 データは 上 から 下 へ biplanes 2 byte プレーン 数 常 に 1 bibitcount 2 byte 1 画 素 あたりのデータサイズ (bit) bicopmression 4 byte 圧 縮 形 式 1-2 色 ビットマップ 4-16 色 ビットマップ 8-256 色 ビットマップ 16-65536 色 (high color)ビットマップ 24-1677 万 色 (true color)ビットマップ 32-1677 万 色 (true color)ビットマップ 0 - BI_RGB ( 無 圧 縮 ) 1 - BI_RLE8 (RunLength 8 bits/pixel) 2 - BI_RLE4 (RunLength 4 bits/pixel) 3 Bitfields
情 報 ヘッダ < Windows > [BITMAPINFOHEADER] BITMAPINFOHEADER (2) bisizeimage 4 byte 画 像 データ 部 のサイズ (byte) 96dpi ならば3780 0 の 場 合 もある bixpixpermeter biypixpermeter biclrused 4 byte 4 byte 4 byte 横 方 向 解 像 度 (1mあたりの 画 素 数 ) 縦 方 向 解 像 度 (1mあたりの 画 素 数 ) 格 納 されているパレット 数 ( 使 用 色 数 ) 96dpi ならば3780 0 の 場 合 もある 96dpi ならば3780 0 の 場 合 もある 0 の 場 合 もある bicirimportant 4 byte 重 要 なパレットのインデックス 0 の 場 合 もある
情 報 ヘッダ < OS/2 > [BITMAPCOREHEADER ] BITMAPCOREHEADER bisize 4 byte 情 報 ヘッダのサイズ (byte) 12 byte bcwidth 2 byte 画 像 の 幅 (ピクセル) bcheight 2 byte 画 像 の 高 さ (ピクセル) bcheight の 値 が 正 数 なら, 画 像 データは 下 から 上 へ bcheight の 値 が 負 数 なら, 画 像 データは 上 から 下 へ bcplanes 2 byte プレーン 数 常 に 1 bcbitcount 2 byte 1 画 素 あたりのデータサイズ (bit) 1-2 色 ビットマップ 4-16 色 ビットマップ 8-256 色 ビットマップ 16-65536 色 (high color) 24-1677 万 色 (true color)ビットマップ 32-1677 万 色 (true color)ビットマップ
Windows BMP 24bit の 構 成 0x42 が B をあらわす 0x4D は? は1 byte を 示 しているおり,16 進 数 で 表 記 している 実 際 は 実 際 には 8 個 のメモリに2 進 数 で 保 存 されている 42 4D BITMAPFILEHEADER ( 14 byte ) BITMAPINFOHEADER ( 40 byte ) Data ( 任 意 のサイズ )
Windows BMP 24bit のデータ 構 造 は1 画 素 をあらわしている (31,0) (31,31) 32 画 素 32 画 素 のWindows BMP 画 像 データは 基 本 的 に 左 下 から 右 上 へ 向 かって 並 んでいるので モニタに 表 示 されるものとは 並 び 順 が 異 なる ( BITMAPINFOHEADER の biheight で 決 まる ) 各 画 素 は Blue (8bit), Green (8bit), Red (8bit) の 3 byteで 表 現 される (0,0) (0,31) たとえば この 画 素 (5,30)が 白 で (5,31)が 黒 だとすると (5,30) (5,31) 実 際 の 計 算 機 に 保 存 されているのは (2 進 数 ) (16 進 数 ) FF FF FF 00 00 00 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
ヘッダを 読 み 込 む 際 の 注 意 事 項 例.BITMAPINFOHEADER の bisize : 情 報 ヘッダのサイズ Windows BMP の 場 合 bisize の 値 は 常 に 40 byte bisizeは4 byte で 保 存 されている 10 進 数 の40を 4 byte の16 進 数 で 表 現 すると 0x00000028 ( 2 16 + 8 = 40) 計 算 機 の 中 では 右 図 のように 格 納 されている ( Intel 系 の 計 算 機 など ) 28 00 00 00 下 位 データ 上 位 データ 下 のように temp_long に 4 byte を 読 み 込 んでみると long temp_long; fread ( &temp_long, 4, 1, fpr ); /* 情 報 ヘッダサイズ */ long infohead_size = temp_long; 40.0
ヘッダを 読 み 込 む 際 の 注 意 事 項 long temp_long; fread ( &temp_long, 4, 1, fpr ); temp_long の 中 身 は 0x00000028 1 前 の データ 28 00 00 00 下 位 データ 上 位 データ 次 の データ であれば 問 題 ないのだが 右 図 のように 認 識 する 計 算 機 もある ( 系 の 計 算 機 )など 前 の データ 28 00 00 00 次 の データ この 場 合 の tmp_long の 中 身 は 0x28000000 2 上 位 データ 下 位 データ こんなに 違 う 1: 0x00000028 = 40 ) 10 2: 0x28000000 =671088640 ) 10
エンディアン たとえば 0x0123ABFF を 格 納 する 場 合 に 2つの 方 式 がある 前 の データ 処 理 ( 書 込 )の 順 番 FF AB 23 01 下 位 データ 上 位 データ 次 の データ 0x0123ABFF リトルエンディアン < 今 回 使 うBMPファイルはこちらに 準 拠 > 前 の データ 処 理 ( 書 込 )の 順 番 01 23 AB FF 上 位 データ 次 の データ 上 位 データ 下 位 データ 0x0123ABFF ビッグエンディアン < 計 算 機 室 のシステムはこちらに 準 拠 >
リトルエンディアンのつもりで 作 られたヘッダ 情 報 が 前 の 次 の データ 28 00 00 00 データ データ 28 00 00 00 前 の 次 の データ 下 位 データ こうすると long temp_long; 上 位 データ 上 位 データ 下 位 データ ビックエンディアンで 認 識 されている! fread ( &temp_long, 4, 1, fpr ); 0x28000000 になってしまうので 上 下 のbyteで 中 身 を 入 れ 替 えないと 正 しい 値 を 得 られない
おまけ fseek 関 数 fseek ( fp, offset, int origin ); 引 数 に 指 定 したファイルポインタの 初 期 位 置 originを 基 準 として,offsetだけ 移 動 する offsetの 単 位 は byte int origin : SEEK_SET (ファイルの 先 頭 ) SEEK_CUR (ファイルの 現 在 位 置 ) SEEK_END (ファイルの 終 端 )
発 展 課 題 : 拡 張 版 BMP 入 出 力 課 題 で 作 成 したプログラムを 任 意 に 拡 張 する 例 ) 画 像 を 反 転 回 転 任 意 の 色 を 強 調 任 意 の 位 置 を 切 り 出 し 24 bit に 限 らず,8 bit, 32 bitなどにも 対 応 ( カラーパレットについて 調 べる 必 要 あり ) OS/2 Bitmapにも 対 応 画 像 フィルタの 適 用 など