回答:
ファイル記述子は、Linuxおよび他のUnixライクなシステムで、カーネルレベルで開かれているファイル(またはソケットなど)を識別するために使用される低レベルの整数「ハンドル」です。
あなたのような実際のUnixの呼び出しに「裸」のファイル記述子を渡すread()
、write()
というように。
FILE
ポインタは、ファイルを表すために使用されるC標準ライブラリレベルの構築物です。のFILE
ファイルディスクリプタをラップし、I / Oを容易にするためのバッファリングやその他の機能が追加されています。
fd
がの最初の引数であることを示していread()
ます。なぜそれを裸と呼ぶのですか?
FILE *
タイプと比較すると、整数ファイル記述子は「ラップが少ない」、つまり「ネイキッド」です。
1つはバッファリングされます(FILE *
)され、もうません。実際には、使用したいFILE *
は、「実際の」ファイル(つまりドライブ上)から読み取るときは、何をしているのかがわからない場合や、ファイルが実際にソケットなどでない限り、ほとんど常にする必要があります。
FILE *
を使用してファイル記述子を取得し、使用してファイル記述子からfileno()
バッファリングさFILE *
れたファイルを開くことができますfdopen()
ファイル記述子は、POSIX open()
呼び出しから取得する単なる整数です。標準C fopen()
を使用すると、FILE
構造体が返されます。FILE
構造体は、このようなエンド・オブ・ファイルなど、エラーインジケータ、ストリーム位置としてとりわけ、このファイルディスクリプタが含まれています
したがって、を使用fopen()
すると、に比べてある程度の抽象化が得られますopen()
。一般にfopen()
、移植性が高く、FILE
構造体、つまり、fprintf()
およびファミリを使用する他のすべての標準C関数を使用できるため、使用する必要があります。
どちらを使用してもパフォーマンスの問題はありません。
ファイル記述子とファイルポインター
ファイル記述子:
ファイル記述子は、open()
システムコールによって返される整数値です。
int fd = open (filePath, mode);
ファイルポインタ:
ファイルポインターは、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;
役に立つかもしれないポイントを追加したい。
約 FILE *
デバッグログに何度も使用しています。例、
FILE *fp;
fp = fopen("debug.txt","a");
fprintf(fp,"I have reached till this point");
fclose(fp);
約 FILE DESCRIPTOR
通常はIPCに使用されます。
* nixシステム上のファイル(デバイス、ファイル、ソケットなど)に低レベルの制御を提供します。したがって、より強力ですFILE *
。
fdopen()
IPCやデバイスなどで使用できませんFILE*
か?
FILE*
がFILE*
、ファイル記述子(fdopen()
)からを作成し、後でを閉じるFILE
と記述子も閉じられます。そのため、次のことができません IPCをしていますが、任意の直接のIPCを容易にするために、少しのファイルディスクリプタに対処する必要があります。
FILE *
あなたは、テキストファイルやユーザー入力/出力を操作するとき、それはあなたのようなAPI関数を使用することができますので、より有用であるsprintf()
、sscanf()
、fgets()
、feof()
など
ファイル記述子APIは低レベルであるため、ソケット、パイプ、メモリマップファイル(および通常のファイル)を操作できます。
ディスカッションを終了するためのメモ(興味がある場合)...
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)
でしょうか?
システムコールは、主に、たとえば、ファイル記述子を使用しているread
と write
。ライブラリ関数はファイルポインタ(printf
、scanf
)を使用します。ただし、ライブラリ関数は内部でシステムコールのみを使用しています。
私はここで良いリソースを見つけ、2つの違いの高レベルの概要を説明しました。
ファイルへの入力または出力を行う場合、プログラムとファイルの間の接続を表すための2つの基本的なメカニズム(ファイル記述子とストリーム)を選択できます。ファイル記述子はint型のオブジェクトとして表され、ストリームはFILE *オブジェクトとして表されます。
ファイル記述子は、入出力操作に対する基本的な低レベルのインターフェースを提供します。ファイル記述子とストリームはどちらも、デバイス(端末など)への接続、または別のプロセスと通信するためのパイプやソケット、および通常のファイルを表すことができます。ただし、特定の種類のデバイスに固有の制御操作を実行する場合は、ファイル記述子を使用する必要があります。この方法でストリームを使用する機能はありません。また、プログラムがノンブロッキング(またはポーリング)入力などの特殊モードで入力または出力を行う必要がある場合は、ファイル記述子を使用する必要があります(ファイルステータスフラグを参照)。
ストリームは、プリミティブファイル記述子機能の上に階層化された、より高レベルのインターフェイスを提供します。ストリームインターフェイスは、すべての種類のファイルをほぼ同じように扱います。唯一の例外は、選択できる3つのスタイルのバッファリングです(ストリームバッファリングを参照)。
ストリームインターフェイスを使用する主な利点は、ストリームに対して実際の入力および出力操作(制御操作ではなく)を実行するための一連の関数が、ファイル記述子の対応する機能よりもはるかに豊富で強力であることです。ファイル記述子インターフェースは、文字のブロックを転送するための単純な関数のみを提供しますが、ストリームインターフェースは、強力なフォーマット済み入出力関数(printfおよびscanf)と、文字および行指向の入出力のための関数も提供します。
ストリームはファイル記述子の観点から実装されているため、ストリームからファイル記述子を抽出し、ファイル記述子に対して直接低レベルの操作を実行できます。また、最初に接続をファイル記述子として開き、そのファイル記述子に関連付けられたストリームを作成することもできます。
一般に、ファイル記述子でのみ実行できる特定の操作が必要な場合を除いて、ファイル記述子ではなくストリームの使用に固執する必要があります。初心者のプログラマーで、使用する関数がわからない場合は、フォーマットされた入力関数(フォーマットされた入力を参照)とフォーマットされた出力関数(フォーマットされた出力を参照)に集中することをお勧めします。
GNU以外のシステムへのプログラムの移植性について懸念がある場合は、ファイル記述子はストリームほど移植性がないことにも注意してください。ISO Cを実行するすべてのシステムがストリームをサポートすることを期待できますが、GNU以外のシステムはファイル記述子をまったくサポートしないか、ファイル記述子を操作するGNU関数のサブセットのみを実装する場合があります。ただし、GNU Cライブラリのファイル記述子関数のほとんどは、POSIX.1標準に含まれています。