C言語のfopenで「w」と「wb」は何が違う?テキストモードとバイナリモードを具体例付きで解説

C言語関連

C言語でファイルを開くとき、fopen()の第2引数には"w"や"wb"のような文字列を指定します。どちらも「書き込み用にファイルを開く」という点は同じですが、wはテキストモード、wbはバイナリモードという違いがあります。

特にWindowsでは、この違いによって改行コードなどが変換されることがあります。一方、LinuxやmacOSなどではテキストモードとバイナリモードの実質的な違いがほとんどない環境もあります。

ファイル入出力を正しく理解するには、単に「文字ならw、画像ならwb」と暗記するだけでなく、テキストモードでは何が変換され、バイナリモードでは何がそのまま保存されるのかを理解することが重要です。

結論:wはテキスト書き込み、wbはバイナリ書き込み

fopen()で"w"を指定すると、ファイルをテキストモードの書き込み用として開きます。例えば次のように使います。

FILE *fp = fopen("sample.txt", "w");

一方、"wb"を指定すると、ファイルをバイナリモードの書き込み用として開きます。

FILE *fp = fopen("sample.bin", "wb");

どちらも書き込み時に、指定したファイルが存在しなければ新しく作成されます。すでに存在する場合は、基本的にファイル内容がいったん空になり、先頭から書き直されます。

「b」はbinaryのb

wbに付いているbは、binary(バイナリ)を意味します。そのため、wはwriteの書き込みモード、wbはwrite binaryの書き込みモードと考えると覚えやすくなります。

同じ考え方で、読み込みには"r"と"rb"、追記には"a"と"ab"があります。

モード 意味
r テキストとして読み込み
rb バイナリとして読み込み
w テキストとして書き込み
wb バイナリとして書き込み
a テキストとして末尾へ追記
ab バイナリとして末尾へ追記

したがって、bが付いているかどうかが、テキストモードとバイナリモードを見分けるポイントです。

一番大きな違いは改行などの変換が行われるかどうか

テキストモードでは、C言語のプログラムが扱う文字と、OS上のテキストファイル表現との間で変換が行われる場合があります。代表的なのが改行です。

C言語では改行を\nで表します。しかしWindowsのテキストファイルでは、改行が一般にCRとLFの2バイト、つまり\r\nとして扱われます。

Windowsで"w"を使ってテキストを書き込む場合、プログラム中の\nがファイルへ書き込まれる際に\r\nへ変換されることがあります。

一方、"wb"ではこのようなテキスト用の変換を行わず、指定したバイト列を基本的にそのまま書き込みます。

具体例でwとwbの違いを見る

例えば次のような文字列を書き込むプログラムを考えます。

fprintf(fp, "ABC\nDEF\n");

Windowsで"w"を使用した場合、ファイル内部では概念的にABC\r\nDEF\r\nという形で保存されることがあります。

これに対して"wb"を使用し、同じバイト列を書き込んだ場合は、\nに相当するLFだけがそのまま保存されます。つまり、1バイト単位でファイル形式を厳密に作りたい場合には、この違いが重要になります。

LinuxやmacOSではwとwbの違いが見えにくい

初心者が混乱しやすい点として、環境によってはwとwbを使い分けても同じように見えることがあります。

LinuxやUnix系の環境では、テキストファイルの改行も通常LF、つまり\nです。そのため、テキストモードで特別な改行変換をする必要がなく、wとwbの結果が実質的に同じになることがあります。

macOSも現在はUnix系の仕組みを採用しているため、多くの場合この違いは表面化しません。しかし、C言語のコードをWindowsでも動かす可能性があるなら、用途に応じてwとwbを正しく選ぶ習慣を付けておくほうが安全です。

テキストファイルなら基本的にwを使う

人間がテキストエディタで読むことを前提としたファイルを書き出す場合は、通常"w"を使います。

例えばログファイル、設定ファイル、CSVファイル、単純な文章ファイルなどが代表例です。

FILE *fp = fopen("result.txt", "w"); fprintf(fp, "score = %d\n", 100); fclose(fp);

この場合、ファイルはテキストとして扱いたいため、通常はwで問題ありません。CSVも文字列として保存する一般的な形式なので、通常はテキストモードを使えます。

画像・音声・独自データ形式ならwbを使う

画像、音声、圧縮ファイル、実行ファイル、独自バイナリ形式など、1バイトでも勝手に変化すると困るデータには"wb"を使います。

例えば画像ファイルのデータ中に、たまたま0x0Aという値が含まれていたとします。これをテキストとして扱い、環境側で別のバイト列へ変換してしまうと、ファイル形式が壊れる可能性があります。

そのため、PNG、JPEG、音声データ、構造体を独自形式として保存したデータなど、バイト列そのものに意味があるデータはバイナリモードで扱うのが基本です。

fwriteを使うならwbを選ぶケースが多い

バイナリファイルでは、fwrite()を使ってデータを書き込むことがよくあります。

例えば整数をそのままファイルへ保存する場合は、次のように書けます。

FILE *fp = fopen("data.bin", "wb"); int value = 12345; fwrite(&value, sizeof(value), 1, fp); fclose(fp);

この場合、人間が読める文字列12345を書いているわけではありません。整数valueがメモリ上で持つバイト表現を保存しています。そのためwbを使用するのが適切です。

fprintfを使うから必ずw、fwriteだから必ずwbとは限らない

初心者向けの目安としては、fprintf()などで文字を書き出す場合はw、fwrite()で生のデータを書き出す場合はwbと覚えても大きくは外れません。

ただし、本質的には使用する関数ではなく、ファイルをテキストとして扱いたいのか、バイト列として厳密に扱いたいのかで判断します。

例えばHTTPや独自プロトコル向けに特定のバイト列を厳密に保存したい場合などは、内容が文字に見えていてもバイナリモードが適していることがあります。

wを使うと既存ファイルの中身は消える

wとwbについて覚えておきたいもう一つの重要な特徴が、既存ファイルへの動作です。

どちらも対象ファイルがすでに存在する場合、正常に開ければ基本的にファイルを切り詰めて長さ0にします。つまり、以前の内容は消えます。

例えばimportant.txtにデータが入っている状態で、fopen("important.txt", "w")を成功させると、以前の内容を保持したまま続きを書く動作にはなりません。

既存の内容を残して末尾へ追加したい場合は、"a"またはバイナリなら"ab"を使います。

w+とwb+は読み書きの両方ができる

モード文字列には+を付けることもできます。例えば"w+"ならテキストモードで読み書きの両方ができ、"wb+"ならバイナリモードで読み書きの両方ができます。

ただし、w+やwb+も既存ファイルを開くと内容を切り詰める点には注意が必要です。

モード 読み込み 書き込み 既存内容
w 不可 可 消える
wb 不可 可 消える
w+ 可 可 消える
wb+ 可 可 消える
a 不可 末尾へ追加 残る
ab 不可 末尾へ追加 残る

モードを選ぶときは「テキストかバイナリか」だけでなく、「読み込みたいか」「上書きしたいか」「追記したいか」も合わせて考える必要があります。

バイナリモードならどのPCでも同じデータになるとは限らない

wbを使えばバイト列を変換せず保存できますが、それだけでバイナリファイルに完全な互換性が生まれるわけではありません。

例えばintをfwrite()でそのまま保存すると、CPUのエンディアン、型のサイズ、構造体のパディングなどによって、別の環境では同じように読めないことがあります。

他のPCや別のプログラミング言語でも読み込めるファイル形式を作りたい場合は、整数を何バイトで保存するか、バイト順をどうするか、文字コードをどうするかなどを明確に決める必要があります。

つまり、wbは「OSによるテキスト変換を避けるための指定」であり、「自動的に移植可能なバイナリ形式を作る機能」ではありません。

fopenが失敗していないか必ず確認する

wでもwbでも、ファイルを必ず開けるとは限りません。保存先に書き込み権限がない、パスが不正、ストレージに問題があるなどの理由でfopen()が失敗する場合があります。

そのため、戻り値がNULLでないことを確認してからファイルを操作します。

FILE *fp = fopen("data.bin", "wb"); if (fp == NULL) { perror("fopen"); return 1; }

この確認をせずにfprintf()やfwrite()へ進むと、プログラムが正常に動作しない原因になります。ファイル入出力ではモード指定と同じくらい重要な基本です。

wとwbの使い分けを簡単に覚える方法

迷ったときは、ファイルの中身を「文字として読むもの」か「バイト列として扱うもの」かで判断すると分かりやすくなります。

保存するもの 基本的な選択
テキスト文章 w
ログ wまたは追記ならa
CSV w
PNG・JPEG wb
音声データ wb
独自バイナリ形式 wb
構造体などの生データ wb

特にWindowsを含む複数OSで動かすプログラムでは、この使い分けを明示しておくと意図が分かりやすくなります。

まとめ:wとwbの違いはテキストモードかバイナリモードか

C言語のfopen()で指定する"w"と"wb"は、どちらも新規作成または上書き用の書き込みモードですが、wはテキストモード、wbはバイナリモードという違いがあります。

テキストモードでは、Windowsなど一部の環境で\nとOS側の改行表現との変換などが行われます。バイナリモードでは、そのようなテキスト用変換を避け、バイト列をそのまま扱います。

文章、ログ、CSVなどなら基本的にw、画像、音声、独自形式など1バイト単位の内容を維持したいファイルならwbと考えると分かりやすいでしょう。また、どちらも既存ファイルを開くと内容を消して先頭から書き直すため、追記したい場合はaまたはabを使います。

コメント

タイトルとURLをコピーしました