web-dev-qa-db-ja.com

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

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

  2. プロセステーブルに複数のファイル記述子が含まれていますか。もしそうなら、なぜ?

314
Nishant

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

同様に、ネットワークソケットを開くと、それは整数で表され、Socket Descriptorと呼ばれます。理解していただけるといいのですが。

484
Tayyab

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

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

98
Beano

馬の口から聞いてください:APUE(Richard Stevens)
カーネルにとって、開いているファイルはすべてファイル記述子によって参照されます。ファイル記述子は負ではない数です。

既存のファイルを開いたり新しいファイルを作成したりすると、カーネルはプロセスにファイルディスクリプタを返します。カーネルは使用中のすべての開いているファイルディスクリプタのテーブルを管理します。ファイル記述子の割り当ては一般に順次的であり、それらは空きファイル記述子のプールからの次の空きファイル記述子としてファイルに割り当てられます。ファイルを閉じると、ファイル記述子は解放され、さらに割り当てることができます。
詳細については、この画像を参照してください。

Two Process

ファイルを読み書きするときは、open()またはcreate()関数呼び出しで返されたファイル記述子でファイルを識別し、次のように使用します。 read()またはwrite()のいずれかに対する引数。
UNIXシステムシェルは、ファイルディスクリプタ0をプロセスの標準入力、ファイルディスクリプタ1を標準出力、およびファイルディスクリプタに関連付けることが慣例です。 標準エラーと2。
ファイル記述子は0からOPEN_MAXの範囲です。ファイルディスクリプタの最大値はulimit -nで取得できます。詳しくは、APUE Bookの第3章を参照してください。

88
Shekhar Kumar

File Descriptorに関するその他のポイント:

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

  2. 0, 1, 2は標準のFDで、プログラムの起動時にシェルの代わりにデフォルトで開かれるSTDIN_FILENOSTDOUT_FILENO、およびSTDERR_FILENOunistd.hで定義)に対応します。

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

  4. 特定のプロセスのためのFDは/proc/$pid/fd(Unixベースのシステム)で見ることができます。

15
Sandeep_black

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

14
Balu

他の答えは素晴らしいものを追加しました。私はちょうど私の2セントを追加します。

ウィキペディアによると、私たちは確かに知っています:ファイル記述子は負でない整数です。私が欠けていると思う最も重要なことは、言うことでしょう:

ファイル記述子はプロセス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 table

あなたは自分自身にこれらのファイル記述子が物理的にどこにあるのか、そして例えば/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)
  • シンボリックリンク
11
prosti

ファイル記述子(FD):

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

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

    これらのファイルは、プログラムが実行されるときはいつでも存在します。ファイルディスクリプタの前に説明したように、これらの各ファイルに関連付けられています。
    ファイルファイル記述子
    標準入力STDIN 0
    標準出力STDOUT 1
    標準エラーSTDERR 2

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

$ ls mydir 2> errorsfile.txt

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

あなたがあなたの答えを得たと思います。

4
Abhishek Kamal

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

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

通常、オペレーティングシステムは各プロセス内の各ファイル番号(つまり、各プロセスツリー/テーブル内)で表します。

このプロセスで使用される最初のファイルはfile0、2番目のファイルはfile1です。三つ目はfile2などです。

このような数字はファイル記述子です。

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

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

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

いくつかのオペレーティングシステムでは、ファイルディスクリプタを使い果たすことができますが、そのようなケースは非常にまれであり、平均的なコンピュータユーザーはそれから心配するべきではありません。

ファイル記述子はグローバル(プロセスAは例えば0で始まり、終わりは1で始まり、プロセスBは2で始まり終わりは3で終わる)などであるかもしれませんが、私の知る限り、通常のオペレーティングシステムではディスクリプタはグローバルではなく、実際にはプロセス固有のものです(プロセスAは0から始まり5で終わり、プロセスBは0から始まり10で終わります)。

3
JohnDoea

ファイル記述子

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

上記のすべての単純化された回答に追加。
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
0
sumitsinghdeode