ファイルディスクリプタ(ファイルディスクリプタ)とは | 意味や読み方など丁寧でわかりやすい用語解説
ファイルディスクリプタ(ファイルディスクリプタ)の意味や読み方など、初心者にもわかりやすいように丁寧に解説しています。
読み方
日本語表記
ファイルディスクリプタ (ファイルディスクリプタ)
英語表記
file descriptor (ファイルディスクリプタ)
用語解説
ファイルディスクリプタとは、コンピュータのオペレーティングシステム(OS)が、プロセスがオープンしているファイルやその他の入出力(I/O)リソースを識別するために使用する、プロセス固有の非負の整数値である。プロセスがファイルに対して読み書きなどの操作を行う際、ファイルの実体を直接指定するのではなく、このファイルディスクリプタを介してOSに指示を出す。これにより、プログラムは抽象化されたインターフェースを通じてファイルシステムとやり取りできる。
コンピュータ上でプログラムが実行されるとき、それは「プロセス」としてOSによって管理される。このプロセスが、ディスク上のデータファイル、キーボード入力、画面出力、ネットワーク通信といった様々なI/Oリソースを利用する際には、まずそのリソースを「オープン」する。OSは、リソースをオープンするたびに、そのリソースを一意に識別するための番号をプロセスに割り当てる。この番号がファイルディスクリプタである。たとえば、多くのUNIX系OSでは、プロセスが起動すると自動的に3つのファイルディスクリプタが割り当てられている。ファイルディスクリプタ0は標準入力(通常はキーボード)、ファイルディスクリプタ1は標準出力(通常は画面)、ファイルディスクリプタ2は標準エラー出力(通常は画面)をそれぞれ指す。これらの特別なファイルディスクリプタは、プログラムがユーザーとの対話やエラーメッセージの表示を行う上で基本的な役割を果たす。
ファイルディスクリプタは、単なる整数値ではあるが、その背後にはOSのカーネルが複雑なデータ構造を管理している。プロセスがopen()システムコールを使ってファイルを開くと、カーネルはまずディスク上のファイルに対応するinode情報を探し、そのファイルにアクセスするためのシステム全体の共有情報(オープンファイルテーブルエントリ)を作成する。このオープンファイルテーブルエントリには、ファイルの現在の読み書き位置(オフセット)、アクセスモード(読み込み専用、書き込み専用など)、そしてファイルが指すinodeテーブルエントリへのポインタなどが含まれる。次に、カーネルはプロセス固有のファイルディスクリプタテーブルに新しいエントリを追加し、そのエントリに、作成したオープンファイルテーブルエントリへのポインタを格納する。そして、このプロセス固有のファイルディスクリプタテーブルのインデックス、つまり整数値が、ファイルディスクリプタとしてプロセスに返される。
これにより、同じファイルを複数のプロセスが同時に開いた場合でも、それぞれのプロセスは独立した読み書き位置を持つことができる。たとえば、プロセスAとプロセスBが同じファイルをオープンした場合、カーネルはファイルAとファイルBそれぞれに対して異なるファイルディスクリプタと、それに対応するオープンファイルテーブルエントリを割り当てる。たとえそれらのオープンファイルテーブルエントリが同じinodeを指していても、オフセット情報はそれぞれのオープンファイルテーブルエントリ内で独立して管理されるため、プロセスAがファイルを読み進めても、プロセスBの読み書き位置には影響しない。ただし、fork()システムコールなどでプロセスが複製された場合、子プロセスは親プロセスのファイルディスクリプタテーブルを継承し、同じオープンファイルテーブルエントリを共有することがある。この場合、親プロセスと子プロセスは同じオフセット情報を共有することになるため、どちらかのプロセスがファイルを読み書きすると、もう一方のプロセスのオフセットも進むことになる。
ファイルディスクリプタは、通常のディスク上のファイルだけでなく、パイプ、ソケット、デバイスファイル(例: シリアルポート、ターミナル)といったさまざまなI/Oリソースに対しても割り当てられる。これはUNIX系OSの「全てはファイルである」という設計思想に基づいている。これにより、プログラムはディスクファイルへの操作と、ネットワーク通信やプロセス間通信といった異なる種類のI/O操作を、read(), write(), close()といった共通のシステムコールとファイルディスクリプタを用いて統一的に扱うことができる。これにより、プログラミングの複雑さを軽減し、柔軟性の高いシステム構築が可能となる。
ファイルディスクリプタの取得はopen()やcreat()といったシステムコールによって行われ、取得したファイルディスクリプタはread(), write(), lseek(), close()といったシステムコールに引数として渡され、実際のI/O操作やファイルポインタの移動、ファイルのクローズが行われる。close()システムコールを呼び出すことで、プロセスはそのファイルディスクリプタを解放し、カーネルも関連するリソース(ファイルディスクリプタテーブルエントリや、共有されていないオープンファイルテーブルエントリなど)を解放する。ファイルディスクリプタは有限なリソースであり、プロセスが同時にオープンできるファイルディスクリプタの数には上限が設定されている。プログラムがファイルディスクリプタをオープンしたままclose()を呼び忘れると、システムのリソースを浪費し、「ファイルディスクリプタリーク」と呼ばれる状態を引き起こす可能性がある。これは、最終的に新しいファイルを開けなくなり、システム全体のパフォーマンス低下やプログラムの異常終了につながることがあるため、プログラム開発においてはファイルディスクリプタの適切な管理と解放が非常に重要となる。
また、dup()やdup2()のようなシステムコールを使用すると、既存のファイルディスクリプタを複製したり、別のファイルディスクリプタにリダイレクトしたりすることもできる。これにより、標準出力をファイルに切り替えたり、複数のファイルディスクリプタが同じオープンファイルを参照するように設定したりすることが可能になる。さらに、fcntl()システムコールを使えば、ファイルディスクリプタに関連付けられた属性、例えば非ブロッキングI/Oモードへの設定や、プロセスがexecシステムコールで別のプログラムを実行した際に、ファイルディスクリプタを自動的にクローズするかどうかといった設定を変更することができる。これらの機能は、高度なI/O制御やプロセス管理において重要な役割を果たす。ファイルディスクリプタは、単なる識別番号でありながら、OSがファイルシステムやI/Oリソースをプロセスに提供するための基盤となる、極めて重要な概念である。