我想知道文件描述符和文件指针之间的区别。
另外,在什么情况下你会使用一个而不是另一个?
文件描述符是一个低级整数“句柄”,用于在 Linux 和其他类 Unix 系统的内核级别标识打开的文件(或套接字,或其他任何东西)。
您将“裸”文件描述符传递给实际的 Unix 调用,如 read()、 write()等。
read()
write()
FILE指针是 C 标准库级结构,用于表示文件。FILE包装了文件描述符,并添加了缓冲和其他特性,使 I/O 更加容易。
FILE
将 FILE指针传递给标准 C 函数,如 fread()和 fwrite()。
fread()
fwrite()
文件描述符只是从 POSIX open()调用中获得的一个整数。使用标准的 C fopen()可以返回一个 FILE结构。FILE结构包含这个文件描述符和其他东西,比如文件结束和错误指示符、流位置等。
open()
fopen()
因此,与 open()相比,使用 fopen()提供了一定量的抽象。一般来说,您应该使用 fopen(),因为它更具可移植性,并且您可以使用所有其他使用 FILE结构的标准 C 函数,即 fprintf()和系列。
fprintf()
使用这两种方法都不存在性能问题。
系统调用大多使用文件描述符,例如 read和 write。库函数将使用文件指针(printf,scanf)。但是,库函数只使用内部系统调用。
read
write
printf
scanf
在处理文本文件和用户输入/输出时,FILE *更有用,因为它允许使用像 sprintf()、 sscanf()、 fgets()、 feof()等 API 函数。
FILE *
sprintf()
sscanf()
fgets()
feof()
文件描述符 API 是低级的,因此它允许使用套接字、管道、内存映射文件(当然还有常规文件)。
一个是缓冲区(FILE *) ,另一个不是。实际上,当您从一个“实际”文件中读取数据时,您几乎总是希望使用 FILE *(即。除非您知道自己在做什么,或者您的文件实际上是一个套接字。.
您可以使用 fileno()从 FILE *获得文件描述符,也可以使用 fdopen()从文件描述符打开缓冲的 FILE *
fileno()
fdopen()
希望添加可能有用的点。
关于 FILE *
我多次使用它来调试日志。 例如,
FILE *fp; fp = fopen("debug.txt","a"); fprintf(fp,"I have reached till this point"); fclose(fp);
ABOUT FILE DESCRIPTOR
FILE DESCRIPTOR
It's generally used for IPC.
Gives low-level control to files on *nix systems.(devices,files,sockets,etc), hence more powerfull than the FILE *.
只是一个结束讨论的笔记(如果感兴趣的话) ... ..。
fopen可能是不安全的,您可能应该使用设置了独占位的 fopen_s或 open。C1X 提供 x模式,所以你可以 fopen与模式 "rx","wx"等。
fopen
fopen_s
open
x
"rx"
"wx"
如果使用 open,可以考虑 open(..., O_EXCL | O_RDONLY,... )或 open(..., O_CREAT | O_EXCL | O_WRONLY,... )。
open(..., O_EXCL | O_RDONLY,... )
open(..., O_CREAT | O_EXCL | O_WRONLY,... )
比如说 不要对 fopen ()和文件创建做任何假设。
文件描述符与文件指针
文件描述符:
文件描述符是由 open()系统调用返回的整数值。
int fd = open (filePath, mode);
文件指针:
文件指针是一个指向由 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;
我发现了一个很好的资源 给你,给出了两者之间差异的高层次概述:
当您想要对文件进行输入或输出时,您可以选择两种基本的机制来表示程序和文件之间的连接: 文件描述符和流。文件描述符表示为 int 类型的对象,而流表示为 FILE * 对象。 文件描述符为输入和输出操作提供一个基本的低级接口。文件描述符和流都可以表示到设备(例如终端)的连接,或用于与另一个进程通信的管道或套接字,以及普通文件。但是,如果希望执行特定于特定类型设备的控制操作,则必须使用文件描述符; 没有任何工具可以以这种方式使用流。如果程序需要以特殊模式进行输入或输出,例如非阻塞(或轮询)输入(参见文件状态标志) ,则还必须使用文件描述符。 流提供了一个更高级别的接口,它位于基本文件描述符工具之上。流接口对待所有类型的文件都非常相似,唯一的例外是可以选择的三种缓冲样式(参见 Stream Buffering)。 使用流接口的主要优点是,用于在流上执行实际输入和输出操作(相对于控制操作)的函数集比文件描述符的相应功能更加丰富和强大。文件描述符接口只提供传输字符块的简单函数,但是流接口还提供强大的格式化输入和输出函数(printf 和 Scanf) ,以及面向字符和行的输入和输出函数。 由于流是以文件描述符的形式实现的,因此可以从流中提取文件描述符,并直接对文件描述符执行低级操作。您还可以首先将连接作为文件描述符打开,然后创建与该文件描述符关联的流。 一般来说,应该坚持使用流而不是文件描述符,除非有一些特定的操作只能在文件描述符上执行。如果您是一个初级程序员,并且不确定使用什么函数,我们建议您专注于格式化的输入函数(请参阅格式化输入)和格式化的输出函数(请参阅格式化输出)。 如果您关心程序对 GNU 以外的系统的可移植性,那么您还应该注意到文件描述符不像流那样可移植。您可以期望任何运行 ISO C 的系统都支持流,但是非 GNU 系统可能根本不支持文件描述符,或者可能只实现一部分在文件描述符上运行的 GNU 函数。然而,GNUCLibrary 中的大多数文件描述符函数都包含在 POSIX.1标准中。
当您想要对文件进行输入或输出时,您可以选择两种基本的机制来表示程序和文件之间的连接: 文件描述符和流。文件描述符表示为 int 类型的对象,而流表示为 FILE * 对象。
文件描述符为输入和输出操作提供一个基本的低级接口。文件描述符和流都可以表示到设备(例如终端)的连接,或用于与另一个进程通信的管道或套接字,以及普通文件。但是,如果希望执行特定于特定类型设备的控制操作,则必须使用文件描述符; 没有任何工具可以以这种方式使用流。如果程序需要以特殊模式进行输入或输出,例如非阻塞(或轮询)输入(参见文件状态标志) ,则还必须使用文件描述符。
流提供了一个更高级别的接口,它位于基本文件描述符工具之上。流接口对待所有类型的文件都非常相似,唯一的例外是可以选择的三种缓冲样式(参见 Stream Buffering)。
使用流接口的主要优点是,用于在流上执行实际输入和输出操作(相对于控制操作)的函数集比文件描述符的相应功能更加丰富和强大。文件描述符接口只提供传输字符块的简单函数,但是流接口还提供强大的格式化输入和输出函数(printf 和 Scanf) ,以及面向字符和行的输入和输出函数。
由于流是以文件描述符的形式实现的,因此可以从流中提取文件描述符,并直接对文件描述符执行低级操作。您还可以首先将连接作为文件描述符打开,然后创建与该文件描述符关联的流。
一般来说,应该坚持使用流而不是文件描述符,除非有一些特定的操作只能在文件描述符上执行。如果您是一个初级程序员,并且不确定使用什么函数,我们建议您专注于格式化的输入函数(请参阅格式化输入)和格式化的输出函数(请参阅格式化输出)。
如果您关心程序对 GNU 以外的系统的可移植性,那么您还应该注意到文件描述符不像流那样可移植。您可以期望任何运行 ISO C 的系统都支持流,但是非 GNU 系统可能根本不支持文件描述符,或者可能只实现一部分在文件描述符上运行的 GNU 函数。然而,GNUCLibrary 中的大多数文件描述符函数都包含在 POSIX.1标准中。