ウィキペディアのものと比べてファイル記述子のより単純化された記述は何でしょうか?なぜ彼らは必要ですか?たとえば、シェルプロセスを例にとると、それはどのように適用されますか。
プロセステーブルに複数のファイル記述子が含まれていますか。もしそうなら、なぜ?
簡単に言うと、ファイルを開くと、オペレーティングシステムはそのファイルを表すエントリを作成し、その開かれたファイルに関する情報を格納します。あなたのOSで100個のファイルが開かれているなら、OSには100個のエントリがあるでしょう(カーネルのどこかに)。これらのエントリは、(... 100、101、102 ...)のような整数で表されます。このエントリ番号はファイル記述子です。そのため、オペレーティングシステムで開かれているファイルを一意に表す整数です。プロセスが10個のファイルを開く場合、Processテーブルにはファイル記述子のエントリが10個あります。
同様に、ネットワークソケットを開くと、それは整数で表され、Socket Descriptorと呼ばれます。理解していただけるといいのですが。
ファイル記述子は、ファイルとソケットのリソースを識別するために、ユーザーとカーネル空間の間のインタフェースで使用される不透明なハンドルです。したがって、open()
またはsocket()
(カーネルとのインタフェースをとるためのシステムコール)を使用すると、ファイルディスクリプタが与えられます。これは整数です(実際にはプロセスのu構造体へのインデックスです - しかし重要ではありません)。したがって、read()
、write()
、close()
などのシステムコールを使用してカーネルと直接やり取りする場合は、使用するハンドルはファイル記述子です。
stdio
インターフェースであるシステムコールにオーバーレイされた抽象化層があります。これは基本的なシステムコールよりも多くの機能/機能を提供します。このインタフェースの場合、取得される不透明なハンドルはFILE*
で、これはfopen()
呼び出しによって返されます。 stdio
インターフェースfprintf()
、fscanf()
、fclose()
を使う関数はたくさんありますが、これらはあなたの人生を楽にするためのものです。 Cでは、stdin
、stdout
、およびstderr
はFILE*
であり、UNIXではそれぞれファイル記述子0
、1
および2
にマッピングされます。
馬の口から聞いてください:APUE(Richard Stevens)
カーネルにとって、開いているファイルはすべてファイル記述子によって参照されます。ファイル記述子は負ではない数です。
既存のファイルを開いたり新しいファイルを作成したりすると、カーネルはプロセスにファイルディスクリプタを返します。カーネルは使用中のすべての開いているファイルディスクリプタのテーブルを管理します。ファイル記述子の割り当ては一般に順次的であり、それらは空きファイル記述子のプールからの次の空きファイル記述子としてファイルに割り当てられます。ファイルを閉じると、ファイル記述子は解放され、さらに割り当てることができます。
詳細については、この画像を参照してください。
ファイルを読み書きするときは、open()またはcreate()関数呼び出しで返されたファイル記述子でファイルを識別し、次のように使用します。 read()またはwrite()のいずれかに対する引数。
UNIXシステムシェルは、ファイルディスクリプタ0をプロセスの標準入力、ファイルディスクリプタ1を標準出力、およびファイルディスクリプタに関連付けることが慣例です。 標準エラーと2。
ファイル記述子は0からOPEN_MAXの範囲です。ファイルディスクリプタの最大値はulimit -n
で取得できます。詳しくは、APUE Bookの第3章を参照してください。
File Descriptor
に関するその他のポイント:
File Descriptors
(FD)は、開かれているファイルに関連付けられている負でない整数(0, 1, 2, ...)
です。
0, 1, 2
は標準のFDで、プログラムの起動時にシェルの代わりにデフォルトで開かれるSTDIN_FILENO
、STDOUT_FILENO
、およびSTDERR_FILENO
(unistd.h
で定義)に対応します。
FDは順番に割り当てられます。つまり、割り当てられていない最小の整数値です。
特定のプロセスのためのFDは/proc/$pid/fd
(Unixベースのシステム)で見ることができます。
他の答えへの追加として、unixはすべてをファイルシステムとみなします。あなたのキーボードはカーネルの観点からのみ読まれるファイルです。画面は書き込み専用ファイルです。同様に、フォルダ、入出力デバイスなどもファイルと見なされます。ファイルが開かれるときはいつでも、(デバイスファイル用の)デバイスドライバがopen()を要求するとき、またはプロセスがユーザファイルを開くとき、カーネルはファイルディスクリプタを割り当てます。 、参考にしてください。[参照: https://en.wikipedia.org/wiki/Everything_is_a_file ]
他の答えは素晴らしいものを追加しました。私はちょうど私の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 - キャラクタ型スペシャルファイル(またはキャラクタ型デバイスファイル)です。
これで、STDIN
、STDOUT
、およびSTDERR
のファイル記述子をlsof -p PID
で簡単に識別できます。または、ls /proc/PID/fd
の場合も同じように表示できます。
また、カーネルが追跡するファイルディスクリプタテーブルは、ファイルテーブルやiノードテーブルと同じではありません。他の答えで説明したように、これらは別々です。
あなたは自分自身にこれらのファイル記述子が物理的にどこにあるのか、そして例えば/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種類のファイルを定義しています。
ファイル記述子(FD):
$ ls mydir 2> errorsfile.txt
標準エラーのファイル記述子は2です。
mydirという名前のディレクトリがない場合、commandの出力はファイルerrorfile.txtに保存されます。
"2>"を使用して、エラー出力を "errorfile.txt"という名前のファイルにリダイレクトします。
したがって、プログラム出力はエラーで雑然としません。
あなたがあなたの答えを得たと思います。
どのオペレーティングシステムでも実行中のプロセス(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で終わります)。
上記のすべての単純化された回答に追加。
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