この記事は私が書いた記事の焼き直しです。
http://d.hatena.ne.jp/temtan/20120723/1343050321
Windows の C 言語環境でファイル入出力を扱う場合、複数の方法があり混乱しやすいので整理してみました。
Windows の C 言語環境の場合、ファイルの入出力関数に関しては複数があり、C 言語標準のファイル入出力関数群、Windows 特有のファイルハンドルを使った関数群、Unix系の関数群を模した低水準ファイル入出力があります。
- ファイルポインタ
- C 言語構造体 FILE のポインタ。fopen 関数でファイルを開いたりして取得するやつ。型は FILE*
- ファイルハンドル
- Windows OS 特有のハンドル。CreateFile 関数で取得したりするやつ。型はHANDLE
- ファイル記述子
- ファイル記述子、ファイルディスクリプタ等と呼ばれる、型が int の値。UNIX でも使われる物に相当。
それぞれは扱う関数が別になっているので例えば Windows特有のファイルハンドルを使って C 言語標準のファイル入出力関数群を使うといったことが出来ない。
ファイルポインタは C 言語標準で C 言語が使える環境なら常に使えるようになっている筈で、後述のファイル記述子は移植性に問題があったが、こちらでは移植性が高く、便利な関数がそろってたりするので扱い易い。C 言語を勉強するときは最初にコレを勉強すると思う。自分も最初はコレだった。
ファイルハンドルは Windows OS 特有のハンドルで管理される。Windows 上で上記二つを扱う場合でも内部的に最終的にはこちらを経由して扱うことになる(と思う)。こちらでファイルアクセスする場合は、とにかく面倒臭い。Win32API の関数がやたら引数と引数に指定するパラメータが多いのでいちいちリファレンスを見ないと扱えない。その代わり細かい制御をしたい場合はこちらでないと出来ないことが多い。
ファイル記述子は UNIX でストリームを扱う際に OS により与えられる整数値。ファイルだけでなくストリーム全般を扱い低水準であるため扱いが色々面倒である部分もある。また、この概念は UNIX でない OS では無い場合もあるので移植性は基本的に無い。
種別 | ファイルポインタ | ファイルハンドル | ファイル記述子 |
---|---|---|---|
型 | FILE* | HANDLE | int |
ファイルを開く | fopen | CreateFile | _open |
読む | fread 等 | ReadFile | _read(注:readではない) |
書く | fwrite 等 | WriteFile | _write(注:writeではない) |
注意点として、ファイル記述子を使う関数は最初にアンダースコアがつくこと。アンダースコアがつかない read と write は windows socket 用の関数であり、ファイルに対しては使えない。この辺混乱しやすい。
そしてそれらの相互に変換する関数群について。
stdio.h | io.h | |||||||
---|---|---|---|---|---|---|---|---|
ファイルポインタ | → | _fileno | → | ファイル記述子 | → | _get_osfhandle | → | ファイルハンドル |
ファイルポインタ | ← | _fdopen | ← | ファイル記述子 | ← | _open_osfhandle | ← | ファイルハンドル |
自分の場合、単純にファイルを開くのではなく、既に開いているパイプだったり、変な方法で開いたファイルだったり色々あってファイルハンドルで取得する場合があったりするのだが、それ用の関数の ReadFile や WriteFile が引数指定が多くて手軽に使えず、慣れているファイルポインタを使った方法を使いたかったので、そういった場合は上記の関数を使い変換して使うようにしている。