文件描述符和文件指针的区别是什么?

我想知道文件描述符和文件指针之间的区别。

另外,在什么情况下你会使用一个而不是另一个?

112702 次浏览

文件描述符是一个低级整数“句柄”,用于在 Linux 和其他类 Unix 系统的内核级别标识打开的文件(或套接字,或其他任何东西)。

您将“裸”文件描述符传递给实际的 Unix 调用,如 read()write()等。

FILE指针是 C 标准库级结构,用于表示文件。FILE包装了文件描述符,并添加了缓冲和其他特性,使 I/O 更加容易。

FILE指针传递给标准 C 函数,如 fread()fwrite()

文件描述符只是从 POSIX open()调用中获得的一个整数。使用标准的 C fopen()可以返回一个 FILE结构。FILE结构包含这个文件描述符和其他东西,比如文件结束和错误指示符、流位置等。

因此,与 open()相比,使用 fopen()提供了一定量的抽象。一般来说,您应该使用 fopen(),因为它更具可移植性,并且您可以使用所有其他使用 FILE结构的标准 C 函数,即 fprintf()和系列。

使用这两种方法都不存在性能问题。

系统调用大多使用文件描述符,例如 readwrite。库函数将使用文件指针(printfscanf)。但是,库函数只使用内部系统调用。

在处理文本文件和用户输入/输出时,FILE *更有用,因为它允许使用像 sprintf()sscanf()fgets()feof()等 API 函数。

文件描述符 API 是低级的,因此它允许使用套接字、管道、内存映射文件(当然还有常规文件)。

一个是缓冲区(FILE *) ,另一个不是。实际上,当您从一个“实际”文件中读取数据时,您几乎总是希望使用 FILE *(即。除非您知道自己在做什么,或者您的文件实际上是一个套接字。.

您可以使用 fileno()FILE *获得文件描述符,也可以使用 fdopen()从文件描述符打开缓冲的 FILE *

希望添加可能有用的点。

关于 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);
    

ABOUT FILE DESCRIPTOR

  1. It's generally used for IPC.

  2. Gives low-level control to files on *nix systems.(devices,files,sockets,etc), hence more powerfull than the FILE *.

只是一个结束讨论的笔记(如果感兴趣的话) ... ..。

fopen可能是不安全的,您可能应该使用设置了独占位的 fopen_sopen。C1X 提供 x模式,所以你可以 fopen与模式 "rx""wx"等。

如果使用 open,可以考虑 open(..., O_EXCL | O_RDONLY,... )open(..., O_CREAT | O_EXCL | O_WRONLY,... )

比如说 不要对 fopen ()和文件创建做任何假设

文件描述符与文件指针

文件描述符:

文件描述符是由 open()系统调用返回的整数值。

int fd = open (filePath, mode);

  1. 低级/内核级处理程序。
  2. 传递到 UNIX 系统调用的 read ()和 write ()。
  3. 不包括缓冲等特性。
  4. 便携性差,效率低。

文件指针:

文件指针是一个指向由 fopen()库函数返回的 C 结构的指针,用于 识别文件、包装文件描述符、缓冲功能和 I/O 操作所需的所有其他功能. 文件指针的类型为 文件,其定义可以在 ”/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. 提供更高的可移植性和效率。

我发现了一个很好的资源 给你,给出了两者之间差异的高层次概述:

当您想要对文件进行输入或输出时,您可以选择两种基本的机制来表示程序和文件之间的连接: 文件描述符和流。文件描述符表示为 int 类型的对象,而流表示为 FILE * 对象。

文件描述符为输入和输出操作提供一个基本的低级接口。文件描述符和流都可以表示到设备(例如终端)的连接,或用于与另一个进程通信的管道或套接字,以及普通文件。但是,如果希望执行特定于特定类型设备的控制操作,则必须使用文件描述符; 没有任何工具可以以这种方式使用流。如果程序需要以特殊模式进行输入或输出,例如非阻塞(或轮询)输入(参见文件状态标志) ,则还必须使用文件描述符。

流提供了一个更高级别的接口,它位于基本文件描述符工具之上。流接口对待所有类型的文件都非常相似,唯一的例外是可以选择的三种缓冲样式(参见 Stream Buffering)。

使用流接口的主要优点是,用于在流上执行实际输入和输出操作(相对于控制操作)的函数集比文件描述符的相应功能更加丰富和强大。文件描述符接口只提供传输字符块的简单函数,但是流接口还提供强大的格式化输入和输出函数(printf 和 Scanf) ,以及面向字符和行的输入和输出函数。

由于流是以文件描述符的形式实现的,因此可以从流中提取文件描述符,并直接对文件描述符执行低级操作。您还可以首先将连接作为文件描述符打开,然后创建与该文件描述符关联的流。

一般来说,应该坚持使用流而不是文件描述符,除非有一些特定的操作只能在文件描述符上执行。如果您是一个初级程序员,并且不确定使用什么函数,我们建议您专注于格式化的输入函数(请参阅格式化输入)和格式化的输出函数(请参阅格式化输出)。

如果您关心程序对 GNU 以外的系统的可移植性,那么您还应该注意到文件描述符不像流那样可移植。您可以期望任何运行 ISO C 的系统都支持流,但是非 GNU 系统可能根本不支持文件描述符,或者可能只实现一部分在文件描述符上运行的 GNU 函数。然而,GNUCLibrary 中的大多数文件描述符函数都包含在 POSIX.1标准中。