FIO14-C. ファイルストリームにおけるテキストモードとバイナリモードの違いを理解する
ファイルに対する入出力は論理データストリームへの入出力として行われる。論理データストリームは各種の入出力の特性を画一的に扱えるようにしたものである。 論理データストリームには、テキストストリームとバイナリストリームの 2 種類がある [ISO/IEC 9899:1999]。テキストストリームとバイナリストリームでは実際のデータ表現が異なり、いくつかの C99 関数の効果も異なる。
テキストストリーム
表現
テキストを表現するためのさまざまな規約に合致させるために、ホスト環境内で文字を変更する必要が生じることがある。そのため、テキストストリームから読み取る、またはテキストストリームに書き込むデータは、ストリームのバイト内容と必ずしも等しくならない。
以下のコードはファイル myfile をテキストストリームとしてオープンする。
char *file_name; /* file_name を初期化 */ FILE *file = fopen(file_name, "w"); /* エラーがないか検査 */ fputs("\n", file);
環境によって改行の表現も異なることがある。たとえば Windows では、このコードは 2 バイト(復帰文字と改行文字)をファイルに書き込むが、POSIX システムでは 1 バイト(改行文字)のみ書き込む。
fseek()
テキストストリームの場合、fseek() に与えるオフセットはゼロ、または SEEK_SET モードで(同じファイルに関連付けられたストリーム上で)以前に呼び出して成功した ftell() 関数からの返り値でなければならない。
ungetc()
ungetc() 関数によって押し戻された文字が読み取られるまで、ファイル位置表示子は未規定である。その結果、これに該当する間は、ファイル位置関連の関数を使用しないように注意する必要がある。
バイナリストリーム
表現
バイナリストリームは、内部データをそのまま記録することのできる順序付けされた文字の並びとする。したがって、バイナリストリームから読み取る、またはバイナリストリームに書き込むデータは、必ずストリームのバイト内容と一致する。
以下のコードはファイル myfile をバイナリストリームとしてオープンする。
char *file_name; /* file_name を初期化 */ FILE *file = fopen(file_name, "wb"); /* エラーがないか検査 */ fputs("\n", file);
環境によらず、このコードは改行文字 1 バイトだけを書き込む。
fseek()
C99 規格によると、バイナリストリームは任意の数の null 文字で終端することができ、SEEK_END を指定した fseek() の呼び出しを意味あるものとしてサポートする必要はない。したがって、バイナリストリームでは、fseek() のモードで SEEK_END を呼び出さないこと。
ungetc()
ungetc() 関数の呼び出しが成功するごとにファイル位置表示子は 1 ずつ減算されるが、呼び出し前の値がゼロのときには呼び出し後の値は不定となる。そのため、ファイル位置表示子がゼロのバイナリストリームでは、ungetc() を呼び出してはならない。
リスク評価
ファイルとストリームの関係を理解していないと、予期せぬ内容のファイルが生成される可能性がある。
レコメンデーション | 深刻度 | 可能性 | 修正コスト | 優先度 | レベル |
---|---|---|---|---|---|
FIO14-C | 低 | 中 | 高 | P2 | L3 |
参考情報
- [ISO/IEC 9899:1999] Section 7.19.2, "Streams"
翻訳元
これは以下のページを翻訳したものです。
FIO14-C. Understand the difference between text mode and binary mode with file streams