続C言語教室 - 第8回 ファイルのオープンモード
今まで単に fopen() を呼び出すことでファイルを開くという操作をしてきましたが、実はいろいろな開き方があります。
基本は「読む」と「書く」で
“r” 読み出しモードで開く。読み出し位置はファイルの先頭。ファイルが存在しなければエラー。
“w” 書き込みモードで開く。書き込み位置はファイルの先頭。ファイルが存在していなければ作られ、存在していれば今までのファイルは長さ0になる(中身が消える)。
これ以外によく使われるのが追加モードで既にあるファイルの続きとして書き込めます。
“a” 追加モードで開く。書き込み位置はファイルの末尾。ファイルが無ければ作られるので w と同じ。
以上のモードで開いたファイルは、読み出しまたは書き込みのどちらかだけが可能で、出来ない方の関数を呼び出すとエラーになります。
これら以外に少し変わったオープンモードもあります。
“r+” 更新モードで開きます。ファイルは存在してなければなりません。読み書き位置はファイルの先頭で、読むことも書くことも出来ます。
“w+” 更新モードで開きます。ファイルが存在していると内容は捨てられます。それ以外は”r+”と同じ。
“a+” 更新モードで開きます。ファイルが存在していなければ”w+”と同じ。存在していれば読み書き位置はファイルの末尾です。
と、ここまでが素直な説明です。UNIX(linux)時代はこれだけで済んでいました。
ところがOSによってはテキストファイルの基本となる改行コードが異なります。元々のUNIXでの改行コードは’\n’(0x0a)ですが、MSDOS(Windows)では”\r\n”(0x0d+0x0a)と2バイト必要です(そして昔のMacは’\r’(0x0d))。このように改行コードが異なるのに同じC言語のソースで処理しようとしたので、MSDOS版のC言語では何も指定しないでファイルを開くと、それは「テキストモード」というモードであるということにして、ライブラリ関数内で自動的に改行コードを変換してくれるという仕様になりました(Macもきっとそうだったんでしょう)。C言語で書かれたプログラムではファイル入出力の際に自動的に改行コードが変換されて’\n’として処理できるようになっているのです。
さて、この機能はfprintfやfscanfといったテキストを処理するような関数だけではなく、freadやfwriteといったバイナリ的な処理をする際にも適用されます。バイト列の中に改行コードに相当する並びがあれば、それも変換されてしまうのです。そんな余計なことをしないでくれという指示をするために「バイナリモード」というものが追加されました(UNIXではモードは無いと言うか、そもそも変換しないので不要)。バイナリモードでファイルを開くには、モード文字列に”b”を追加します。ちなみに”+”のある時は、その前でも後でも同じです(”rb+”と”r+b”は同じ意味)。テキスト以外の処理をするときには、バイナリモードを使わないと予想外の事態を招くので、こちらを指定しましょう。
ちなみにテキストモードでも変換処理が入るために、ファイルの読み書き位置などが不思議な変化をすることがあります。よく考えれば分かるのですが、1文字書いたつもりで2つ進むことがあるんですよね。またOSではなくネットワーク上のプロトコル(HTTPなど)では改行はCR+LF(”\r\n”)と明確に規定されているので、ここは正しく処理しなければならないので、ライブラリ関数内の変換に任せずに自分で処理する場合もバイナリモードが無難です。ネットワークを介してファイルをやりとりすると、ファイルの中身は必ずしも自分のプログラムが動作しているOSの改行コードになっているか怪しいので、1行読むつもりがファイルを最後まで読んでしまう(そしてメモリが足りなくなる)なんていうことも、ママあるので、読む時はどの改行コードでも認識し、書く時は自分のOSの改行コードに統一するなんて言う小細工が必要になったりします。
ちなみにバイナリモードはファイルのオープンモード以外の方法で指定することも出来る場合があるので、既存のコードを使う時は、そちらで制御したほうが良いかもしれません。
テキスト モードとバイナリ モードのファイル入出力
さて、ファイルって同じファイルをひとつのプログラムでも異なるファイル構造体でいくつも開くことが出来ますし、他のプログラムからも開くことが出来ます。何箇所で開こうとも読むだけなら問題ありませんが、書くと何が起こるのでしょうか。次回はそのあたりの話で。
#C言語 #プログラミング #プログラミング講座 #ファイル入出力 #オープンモード #テキスト #バイナリ #改行コード