簡単に説明すると、ファイル記述子とは何ですか?


383
  1. ウィキペディアのものと比較して、ファイル記述子のより単純化された記述は何でしょうか?なぜそれらが必要なのですか?たとえば、シェルプロセスを例に取って、それをどのように適用しますか?

  2. プロセステーブルに複数のファイル記述子が含まれていますか?はいの場合、なぜですか?


3
stdin stdout stderrなどの概念についてはどうですか?例えば、ブラウザプロセスが開かれているようなインスタンスがあり、それは私のhtmlを表示するための一時ファイルをいくつか開いています。プロセスは同じfdを使用して読み取り/書き込みを行いますか?また、プロセステーブル.......には、fd0ポインタfd1ポインタfd2ポインタ.....のようなエントリがあります。これらのファイルはすべてRAMにあるということですか。なぜ他のポインタ?
Nishant 2011年

43
ファイルを開くと、OSはそのファイルへのストリームを作成し、そのストリームを開かれたファイルに接続します。記述子は、実際にはそのストリームを表します。同様に、OSによって作成されたデフォルトのストリームがいくつかあります。これらのストリームは、ファイルではなく端末に接続されます。したがって、ターミナルで何かを書き込むと、標準入力ストリームとOSに送られます。また、ターミナルで「ls」コマンドを書き込むと、OSは出力をstdoutストリームに書き込みます。stdoutストリームがモニター端末に接続されているため、そこで出力を確認できます。
Tayyab

1
ブラウザの例については、ブラウザがファイルを開いたままにしておく必要はありません。ブラウザの実装に依存しますが、ほとんどの場合、ブラウザは一時ファイルを開き、ファイルを書き込み、ファイルを閉じます。そのため、Webページが開いていても、ファイルを開く必要はありません。また、記述子はファイルの情報を保持するだけで、必ずしもファイルをRAMに保持するわけではありません。ディスクリプタからデータを読み取ると、OSはハードディスクからデータを読み取ります。ファイルディスクリプタ内の情報だけでなど。ハード・ディスク上のファイルの場所を表し
Tayyab

5
ファイル記述子からファイルへのマッピングは、1対1のマッピングではありません。同じファイルを4回open()して、4つの異なるファイル記述子を取得できます。それぞれ、(open()に渡されるフラグに応じて)読み取り、書き込み、またはその両方に使用できます。ファイルがRAMにあるかディスクにあるかに関わらず、これはカーネルとそのさまざまなキャッシュによってユーザーから隠されています。最終的に、キャッシュとはディスク上のデータと一致し(書き込み用)、データが既にキャッシュにある場合、カーネルはディスクに戻って読み取りを行いません。
Beano

7
これは簡単に理解できる良い記事ですbottomupcs.com/file_descriptors.xhtml
Krishan Gopal

回答:


561

簡単に言うと、ファイルを開くと、オペレーティングシステムはそのファイルを表すエントリを作成し、開かれたファイルに関する情報を保存します。したがって、OSで100個のファイルが開かれている場合、OS(カーネルのどこか)には100個のエントリがあります。これらのエントリは、(... 100、101、102 ....)のような整数で表されます。このエントリ番号はファイル記述子です。したがって、オペレーティングシステムで開かれたファイルを一意に表すのは単なる整数です。プロセスが10個のファイルを開く場合、プロセステーブルにはファイル記述子の10個のエントリがあります。

同様に、ネットワークソケットを開くと、それも整数で表され、ソケット記述子と呼ばれます。御理解いただけることを願います。


7
また、一度に多数のファイルを開くと、ファイル記述子が不足する可能性があります。これは、* nixシステムが記述子を/proc常に開くため、実行を妨げます。
スペンサーラス

8
@ErbenMo:いいえ、同じではないかもしれません。ファイルを開くと、オペレーティングシステムは使用可能なFDを割り当て、それを閉じるとOSがFDを解放し、そのFDをその後開かれる別のファイルに割り当てる場合があります。オープンファイルを追跡するオペレーティングシステムの方法で、特定のファイルとは関係ありません。
Tayyab 2014年

49
つまり、オペレーティングシステムで開かれたファイルを一意に表すのは単なる整数です。」これは不正解です。その整数は、プロセス内で開かれたファイルを一意に表します。たとえば、ファイル記述子0は、あるプロセスで開いている1つのファイルと、別のプロセスで開いている完全に異なるファイルを表します。
Keith Thompson

15
@Tayyab:私はあなたが間違っていると思います。ファイル記述子0、1、および2は、実行中のプロセスの標準入力、標準出力、および標準エラーです。成功した最初の呼び出しがするopen()別の実行中のプロセスを参照してください。3.ファイルディスクリプタ持ってしまった場合でも、あなたのファイルディスクリプタ3を与えるのPOSIX定義をopen():「open()関数が最も低いという名前のファイルのファイルディスクリプタを返しますそのプロセスに対して現在開いていないファイル記述子です。 " (強調を追加)。
キース・トンプソン

17
@キーストンプソン:はいあなたは正しいです。実際には、抽象化のレベルについてです。実際には2つのテーブルが維持され、最初のテーブルはプロセスごとで、2番目のテーブルはシステム全体です。プロセスごとのテーブル(つまり、fdtable)のFDは、システム全体で一意ではありません。ただし、システム全体の一意のエントリを含むvノードテーブルにマップされます。したがって、fopen()およびfileno()関数を呼び出して記述子を確認すると、2つの異なるプロセスで同じFD番号を取得できます。これは、プロセスごとのfdtableのインデックスを返すためです。よろしくお願いします!!
Tayyab、2016年

116

ファイル記述子は、ファイルとソケットのリソースを識別するためにユーザーとカーネル空間間のインターフェースで使用される不透明なハンドルです。したがって、open()またはsocket()(カーネルへのインターフェイスへのシステムコール)を使用すると、整数であるファイル記述子が与えられます(これは実際にはプロセスのu構造へのインデックスですが、重要ではありません)。したがって、あなたがシステムコールを使用して、カーネルと直接インタフェースしたい場合はread()write()close()などの使用ハンドルはファイルディスクリプタです。

stdioインターフェースであるシステムコールにオーバーレイされた抽象化の層があります。これにより、基本的なシステムコールよりも多くの機能/機能が提供されます。このインターフェースの場合、取得する不透明なハンドルはFILE*であり、fopen()呼び出しによって返されます。使用する多くの多くの機能がありますstdioインターフェイスはfprintf()fscanf()fclose()あなたの人生を容易にするためにそこにです。Cにおいて、stdinstdout、及びstderrでありFILE*、UNIXにそれぞれのファイル記述子にマップされ01そして2


6
私は個人的に、この回答は回答としてマークされたものよりも優れていると思います。賛成。
Tarik

101

馬の口から聞いてください:APUE(リチャード・スティーブンス)。
カーネルにとって、開いているすべてのファイルはファイル記述子によって参照されます。ファイル記述子は負でない数です。

既存のファイルを開くか、新しいファイルを作成すると、カーネルはファイル記述子をプロセスに返します。 カーネルは、使用中のすべてのオープンファイル記述子のテーブルを保持します。ファイル記述子の割り当ては、通常、順次であり、空きファイル記述子のプールからの次の空きファイル記述子としてファイルに割り当てられます。ファイルを閉じると、ファイル記述子が解放され、さらに割り当てることができます。
詳細については、この画像を参照してください。

2つのプロセス

ファイルの読み取りまたは書き込みを行う場合、open()またはcreate()関数呼び出しによって返されたファイル記述子でファイルを識別し、それをread()またはwrite()の引数として使用します。
慣例により、UNIXシステムシェルは、ファイル記述子0をプロセスの標準入力に関連付け、ファイル記述子1を標準出力に関連付け、ファイル記述子2を標準エラーに関連付けます。
ファイル記述子の範囲は0〜OPEN_MAXです。ファイル記述子の最大値はで取得できますulimit -n。詳細については、APUE Bookの第3章を参照してください。


1
0、1、2はプロセスの「stdin」、「stdout」、および「stderr」に関連付けられているので、異なるプロセスに対してこれらの記述子を同時に使用できますか?
Tarik

@Tarik:ファイル記述子はプロセスごとです。これを確認するには、osqueryをダウンロードosqueryi <<< echo '.all process_open_files'してbashシェルで実行します。
Ben Creasy、2017年

29

他の答えは素晴らしいものを追加しました。私は私の2セントだけを追加します。

Wikipediaによると、ファイル記述子は負ではない整数です。私が欠けていると思う最も重要なことは、言うことでしょう:

ファイル記述子はプロセスIDにバインドされます。

私たちは、最も有名なファイルディスクリプタが0、1、2 0に対応している知っているSTDIN、1にSTDOUT、そして2 STDERR

たとえば、シェルプロセスを例に取って、それをどのように適用しますか?

このコードをチェックしてください

#>sleep 1000 &
[12] 14726

id 14726(PID)のプロセスを作成しました。を使用すると、lsof -p 14726次のようになります。

COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
sleep   14726 root  cwd    DIR    8,1     4096 1201140 /home/x
sleep   14726 root  rtd    DIR    8,1     4096       2 /
sleep   14726 root  txt    REG    8,1    35000  786587 /bin/sleep
sleep   14726 root  mem    REG    8,1 11864720 1186503 /usr/lib/locale/locale-archive
sleep   14726 root  mem    REG    8,1  2030544  137184 /lib/x86_64-linux-gnu/libc-2.27.so
sleep   14726 root  mem    REG    8,1   170960  137156 /lib/x86_64-linux-gnu/ld-2.27.so
sleep   14726 root    0u   CHR  136,6      0t0       9 /dev/pts/6
sleep   14726 root    1u   CHR  136,6      0t0       9 /dev/pts/6
sleep   14726 root    2u   CHR  136,6      0t0       9 /dev/pts/6

4番目の列FDとそのすぐ隣の列TYPEは、ファイル記述子とファイル記述子のタイプに対応しています。

FDの値には、次のものがあります。

cwd – Current Working Directory
txt – Text file
mem – Memory mapped file
mmap – Memory mapped device

しかし、実際のファイル記述子は以下のとおりです。

NUMBER – Represent the actual file descriptor. 

数字の後の文字「1u」は、ファイルが開かれているモードを表します。読み取りの場合はr、書き込みの場合はw、読み取りと書き込みの場合はu。

TYPEは、ファイルのタイプを指定します。TYPEの値の一部は次のとおりです。

REG – Regular File
DIR – Directory
FIFO – First In First Out

ただし、すべてのファイル記述子はCHR –キャラクタースペシャルファイル(またはキャラクターデバイスファイル)です。

今、私たちは、のファイル記述子を識別することができSTDINSTDOUTかつSTDERR簡単でlsof -p PID、あるいは我々ならば、私たちは同じことを見ることができますls /proc/PID/fd

また、カーネルが追跡するファイル記述子テーブルは、ファイルテーブルやiノードテーブルとは異なります。他のいくつかの答えが説明したように、これらは別々です。

fdテーブル

これらのファイル記述子は物理的にどこにあり/dev/pts/6、たとえば何に格納されているかを自問することができます

sleep   14726 root    0u   CHR  136,6      0t0       9 /dev/pts/6
sleep   14726 root    1u   CHR  136,6      0t0       9 /dev/pts/6
sleep   14726 root    2u   CHR  136,6      0t0       9 /dev/pts/6

まあ、/dev/pts/6純粋に記憶に住んでいます。これらは通常のファイルではなく、いわゆるキャラクターデバイスファイルです。あなたはこれをチェックすることができます:ls -l /dev/pts/6そしてc、私の場合、それらはで始まりcrw--w----ます。

OSのようなほとんどのLinuxでは、7種類のファイルが定義されています。

  • 通常のファイル
  • ディレクトリ
  • キャラクターデバイスファイル
  • デバイスファイルをブロックする
  • ローカルドメインソケット
  • 名前付きパイプ(FIFO)および
  • シンボリックリンク

1
ありがとう。実際、それがプロセスごとであることを指摘することが重要です!物事をよりよく視覚化するのに役立ちます。
Nishant

1
あなたが答えた中であなたが述べた、OSによって定義されたファイルのタイプは、より低いレベルのファイルを理解するのに本当に役立ちます。
Rohan Bhale

20

その他のポイントFile Descriptor

  1. File Descriptors(FD)は(0, 1, 2, ...)、開かれているファイルに関連付けられている負でない整数です。

  2. 0, 1, 2に対応する標準FDSTDIN_FILENOSTDOUT_FILENOあり、プログラムの起動時にシェルに代わってデフォルトで開かれますSTDERR_FILENO(で定義unistd.h)。

  3. FDは順番に割り当てられます。つまり、割り当て可能な最小の整数値です。

  4. 特定のプロセスのFDは/proc/$pid/fd(UNIXベースのシステムでは)で確認できます。


16

他の回答への追加として、unixはすべてをファイルシステムと見なします。キーボードは、カーネルの観点からのみ読み取られるファイルです。画面は書き込み専用ファイルです。同様に、フォルダー、入出力デバイスなどもファイルと見なされます。ファイルが開かれるとき、たとえば、デバイスドライバー[デバイスファイル用]がopen()を要求するとき、またはプロセスがユーザーファイルを開くとき、カーネルはファイル記述子を割り当てます。これは、読み取り専用のファイルへのアクセスを指定する整数です。 、書き込みのみなど[参照:https : //en.wikipedia.org/wiki/Everything_is_a_file ]


ファイル記述子は、匿名パイプやネットワークソケットなど、ファイルシステムに存在しないものも参照できます。
kbolino 2018年

12

ファイル記述子(FD):

  • Linux / Unixの、すべてがファイルです。通常のファイル、ディレクトリ、さらにはデバイスもファイルです。すべてのファイルには、ファイル記述子(FD)と呼ばれる関連番号があります。
  • 画面にはファイル記述子もあります。プログラムが実行されると、出力が画面のファイル記述子に送信され、モニターにプログラム出力が表示されます。出力がプリンターのファイル記述子に送信される場合、プログラム出力は印刷されます。

    エラーリダイレクト:
    端末でプログラム/コマンドを実行するときは常に、3つのファイルが常に開いています
    1. 標準入力
    2. 標準出力
    3. 標準エラー。

    これらのファイルは、プログラムの実行時に常に存在します。前に説明したように、ファイル記述子は、これらの各ファイルに関連付けられています。
    ファイル                                        ファイル記述子
    標準入力STDIN 0
    標準出力STDOUT 1
    標準エラーSTDERR 2

  • たとえば、ファイルを検索しているときに、通常、権限拒否エラーやその他の種類のエラーが発生します。これらのエラーは特定のファイルに保存できます。
    例1

$ ls mydir 2> errorsfile.txt

標準エラーのファイル記述子は2
です。mydirという名前のディレクトリがない場合、コマンドの出力はファイルerrorfile.txtに保存されます。
「2>」を使用して、エラー出力を「errorfile」というファイルにリダイレクトします。 txt "
したがって、プログラム出力はエラーで乱雑になりません。

答えが出たらいいのに。


5

どのオペレーティングシステムでも、p1、p2、p3などのプロセス(p)が実行されています。通常、各プロセスはファイルを継続的に使用します。

各プロセスは、プロセスツリー(または別の言い回しではプロセステーブル)で構成されています。

通常、オペレーティングシステムは表して、各プロセスの各ファイルによって(各プロセスツリー/テーブルに、と言うことです)。

プロセスで使用される最初のファイルであるfile0秒、FILE1第三の、あるFILE2など、および。

そのような番号はファイル記述子です。

通常、ファイル記述子は整数です(0、1、2ではなく、0.5、1.5、2.5ではありません)。

プロセスを「プロセステーブル」として説明することが多く、テーブルに行(エントリ)があることを考えると、各エントリのファイル記述子セルは、エントリ全体を表すために使用されていると言えます。

同様に、ネットワークソケットを開くと、ソケット記述子があります。

一部のオペレーティングシステムでは、ファイル記述子が不足する可能性がありますが、そのようなケースは非常にまれであり、平均的なコンピューターユーザーは心配する必要はありません。

ファイル記述子はグローバルである可能性があります(プロセスAは0で始まり、1で終わる;プロセスBは2で始まり、3で終わる)などですが、私が知る限り、通常、最新のオペレーティングシステムでは、ファイル記述子はグローバルではなく、実際にはプロセス固有です(プロセスAは0で始まり、たとえば5で終わりますが、プロセスBは0で始まり、たとえば10で終わります)。


:ここでは、LinuxでFDの上もっと読むunix.stackexchange.com/questions/358022/...

1
すばらしい答え:)
humble_wolf

5

ファイル記述子

  • カーネルに対して、開いているすべてのファイルはファイル記述子によって参照されます。
  • ファイル記述子は負でない整数です。
  • 既存のファイルを開くか、新しいファイルを作成すると、カーネルはファイル記述子をプロセスに返します。
  • ファイルの読み取りまたは書き込みを行う場合、読み取りまたは書き込みの引数として、openまたはcreateによって再調整されたファイル記述子でファイルを識別します。
  • 各UNIXプロセスには20のファイル記述子があり、0から19の番号が付けられていますが、多くのシステムによって63に拡張されています。
  • 最初の3つは、プロセスの開始時にすでに開かれています0:標準入力1:標準出力2:標準エラー出力
  • 親プロセスがプロセスをフォークすると、子プロセスは親のファイル記述子を継承します

1

上記すべての簡略化された応答への追加。
bashスクリプトでファイルを操作している場合は、ファイル記述子を使用することをお勧めします。
例:-
ファイル「test.txt」の読み取りと書き込みを行います。
以下に示すようにファイル記述子を使用します

FILE=$1 # give the name of file in the command line
exec 5<>$FILE # '5' here act as the file descriptor
# Reading from the file line by line using file descriptor
while read LINE; do
    echo "$LINE"
done <&5

# Writing to the file using descriptor
echo "Adding the date: `date`" >&5 
exec 5<&- # Closing a file descriptor

-5

ファイル記述子は、ファイルの記述子です。ファイルへのリンクを提供します。それらの助けを借りて、私たちはファイルを読み、書き、そして開くことができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.