ファイル記述子とファイルポインターの違いは何ですか?


回答:


144

ファイル記述子は、Linuxおよび他のUnixライクなシステムで、カーネルレベルで開かれているファイル(またはソケットなど)を識別するために使用される低レベルの整数「ハンドル」です。

あなたのような実際のUnixの呼び出しに「裸」のファイル記述子を渡すread()write()というように。

FILEポインタは、ファイルを表すために使用されるC標準ライブラリレベルの構築物です。のFILEファイルディスクリプタをラップし、I / Oを容易にするためのバッファリングやその他の機能が追加されています。

およびFILEなどの標準C関数にポインタを渡します。fread()fwrite()


@nvl:fildesは確実にWindowsで利用可能です。例:msdn.microsoft.com/en-us/library/z0kc8e3z%28VS.80%29.aspx
kennytm

2
@unwind「ネイキッド」ファイル記述子とはどういう意味ですか?リンクされた参照は、fdがの最初の引数であることを示していread()ます。なぜそれを裸と呼ぶのですか?
オタク2014

3
@Geek標準ライブラリのFILE *タイプと比較すると、整数ファイル記述子は「ラップが少ない」、つまり「ネイキッド」です。
アンワインド

57

1つはバッファリングされます(FILE *)され、もうません。実際には、使用したいFILE *は、「実際の」ファイル(つまりドライブ上)から読み取るときは、何をしているのかがわからない場合や、ファイルが実際にソケットなどでない限り、ほとんど常にする必要があります。

FILE *を使用してファイル記述子を取得し、使用してファイル記述子からfileno()バッファリングさFILE *れたファイルを開くことができますfdopen()


12
fileno()を指摘するための+ 1、manページの構成により、これを見つけるのは困難です。fdopen()についても同じです。
RivenhillでのBD

20

ファイル記述子は、POSIX open()呼び出しから取得する単なる整数です。標準C fopen()を使用すると、FILE構造体が返されます。FILE構造体は、このようなエンド・オブ・ファイルなど、エラーインジケータ、ストリーム位置としてとりわけ、このファイルディスクリプタが含まれています

したがって、を使用fopen()すると、に比べてある程度の抽象化が得られますopen()。一般にfopen()、移植性が高く、FILE構造体、つまり、fprintf()およびファミリを使用する他のすべての標準C関数を使用できるため、使用する必要があります。

どちらを使用してもパフォーマンスの問題はありません。


8
可搬性を高めるための+1。FILEは標準Cライブラリの一部です(C89 / C90に戻る)。ファイル記述子はそうではありません。
tomlogic 2010年

15

ファイル記述子とファイルポインター

ファイル記述子:

ファイル記述子は、open()システムコールによって返される整数値です。

int fd = open (filePath, mode);

  1. 低/カーネルレベルハンドラー。
  2. UNIXシステムコールのread()およびwrite()に渡します。
  3. バッファリングなどの機能は含まれていません。
  4. 移植性が低く、効率が悪い。

ファイルポインタ:

ファイルポインターは、fopen()ライブラリー関数によって返されるC構造体へのポインターです。これは、ファイルの識別、ファイル記述子のラップ、バッファー機能、および入出力操作に必要なその他のすべての機能に使用されます。ファイルポインターのタイプはFILEで、その定義は見つけることができる「/usr/include/stdio.hです」。この定義は、コンパイラによって異なる場合があります。

FILE *fp = fopen (filePath, mode);

// A FILE Structure returned by fopen 
    typedef struct 
    {
        unsigned char   *_ptr;
        int     _cnt;
        unsigned char   *_base;
        unsigned char   *_bufendp;
        short   _flag;
        short   _file;
        int     __stdioid;
        char    *__newbase;
#ifdef _THREAD_SAFE
        void *_lock;
#else
        long    _unused[1];
#endif
#ifdef __64BIT__
        long    _unused1[4];
#endif /* __64BIT__ */
    } FILE;
  1. 高度なインターフェースです。
  2. fread()およびfwrite()関数に渡されます。
  3. バッファリング、エラー表示、EOF検出などが含まれます。
  4. より高い移植性と効率を提供します。

1
そのより高い効率の主張をバックアップできますか?聞いたことがない。
2016年

1
「効率」の主張は、バッファリングが原因である可能性があります。ファイル記述子を使用すると、すべてのread()またはwrite()はsyscallであり、すべてのsyscallは高価であると見なされます。FILE *の場合、バッファリングは、一部の読み取りと書き込みがsyscallにならないことを意味します。
マイクスピア

12

役に立つかもしれないポイントを追加したい。

FILE *

  1. プロセス間通信(IPC)には使用できません。
  2. 汎用バッファI / Oが必要な場合に使用します(printf、frpintf、snprintf、scanf)。
  3. デバッグログに何度も使用しています。例、

                 FILE *fp;
                 fp = fopen("debug.txt","a");
                 fprintf(fp,"I have reached till this point");
                 fclose(fp);

FILE DESCRIPTOR

  1. 通常はIPCに使用されます。

  2. * nixシステム上のファイル(デバイス、ファイル、ソケットなど)に低レベルの制御を提供します。したがって、より強力ですFILE *


fdopen()IPCやデバイスなどで使用できませんFILE*か?
osvein 2017年

実際には、はいといいえの両方。を使用してIPCをセットアップおよび初期化することはできませんFILE*FILE*、ファイル記述子(fdopen())からを作成し、後でを閉じるFILEと記述子も閉じられます。そのため、次のことができません IPCをしていますが、任意の直接のIPCを容易にするために、少しのファイルディスクリプタに対処する必要があります。
Micah W、

3

FILE *あなたは、テキストファイルやユーザー入力/出力を操作するとき、それはあなたのようなAPI関数を使用することができますので、より有用であるsprintf()sscanf()fgets()feof()など

ファイル記述子APIは低レベルであるため、ソケット、パイプ、メモリマップファイル(および通常のファイル)を操作できます。


1
+1は、メモリマップファイルを追加したためです。現在の読み取り時点では、他の回答は既に提供されています。
ernie.cordell 14

3

ディスカッションを終了するためのメモ(興味がある場合)...

fopen安全ではない可能性があり、おそらく、fopen_sまたはopen排他ビットセットを使用する必要があります。C1Xはxモードを提供しているのでfopen、モード"rx""wx"など、

を使用する場合open、検討するopen(..., O_EXCL | O_RDONLY,... )か、open(..., O_CREAT | O_EXCL | O_WRONLY,... )

たとえば、「fopen()とファイルの作成について想定しない」を参照してください。


以下のようfopen_sで利用可能ではないようですPOSIX、私はほとんどのポータブルsoultionをすることであろうと想定open(2)してからfdopen(2)。(窓を脇に置きます)。また、何が速くなるfopen_s()か、open(2)後に続くのfdopen(2)でしょうか?
Mihir

1

システムコールは、主に、たとえば、ファイル記述子を使用しているreadwrite。ライブラリ関数はファイルポインタ(printfscanf)を使用します。ただし、ライブラリ関数は内部でシステムコールのみを使用しています。


ライブラリ関数が内部システムコールのみを使用していると言っている理由がわかりません。標準のCI / O(またはその他の問題)関数を意味している場合、それが(普遍的に?)本当かどうかはわかりません。そうでなければ、それはあなたが言ったことではないので、私はあなたの投稿の言語を少し片付けたいと思います。最後の文は私を困惑させます。
ernie.cordell 2014

1

私はここで良いリソースを見つけ、2つの違いの高レベルの概要を説明しました。

ファイルへの入力または出力を行う場合、プログラムとファイルの間の接続を表すための2つの基本的なメカニズム(ファイル記述子とストリーム)を選択できます。ファイル記述子はint型のオブジェクトとして表され、ストリームはFILE *オブジェクトとして表されます。

ファイル記述子は、入出力操作に対する基本的な低レベルのインターフェースを提供します。ファイル記述子とストリームはどちらも、デバイス(端末など)への接続、または別のプロセスと通信するためのパイプやソケット、および通常のファイルを表すことができます。ただし、特定の種類のデバイスに固有の制御操作を実行する場合は、ファイル記述子を使用する必要があります。この方法でストリームを使用する機能はありません。また、プログラムがノンブロッキング(またはポーリング)入力などの特殊モードで入力または出力を行う必要がある場合は、ファイル記述子を使用する必要があります(ファイルステータスフラグを参照)。

ストリームは、プリミティブファイル記述子機能の上に階層化された、より高レベルのインターフェイスを提供します。ストリームインターフェイスは、すべての種類のファイルをほぼ同じように扱います。唯一の例外は、選択できる3つのスタイルのバッファリングです(ストリームバッファリングを参照)。

ストリームインターフェイスを使用する主な利点は、ストリームに対して実際の入力および出力操作(制御操作ではなく)を実行するための一連の関数が、ファイル記述子の対応する機能よりもはるかに豊富で強力であることです。ファイル記述子インターフェースは、文字のブロックを転送するための単純な関数のみを提供しますが、ストリームインターフェースは、強力なフォーマット済み入出力関数(printfおよびscanf)と、文字および行指向の入出力のための関数も提供します。

ストリームはファイル記述子の観点から実装されているため、ストリームからファイル記述子を抽出し、ファイル記述子に対して直接低レベルの操作を実行できます。また、最初に接続をファイル記述子として開き、そのファイル記述子に関連付けられたストリームを作成することもできます。

一般に、ファイル記述子でのみ実行できる特定の操作が必要な場合を除いて、ファイル記述子ではなくストリームの使用に固執する必要があります。初心者のプログラマーで、使用する関数がわからない場合は、フォーマットされた入力関数(フォーマットされた入力を参照)とフォーマットされた出力関数(フォーマットされた出力を参照)に集中することをお勧めします。

GNU以外のシステムへのプログラムの移植性について懸念がある場合は、ファイル記述子はストリームほど移植性がないことにも注意してください。ISO Cを実行するすべてのシステムがストリームをサポートすることを期待できますが、GNU以外のシステムはファイル記述子をまったくサポートしないか、ファイル記述子を操作するGNU関数のサブセットのみを実装する場合があります。ただし、GNU Cライブラリのファイル記述子関数のほとんどは、POSIX.1標準に含まれています。

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