我想知道文件描述符和文件指针之间的区别。
此外,在什么情况下你会使用一个而不是另一个?
答案 0 :(得分:129)
文件描述符是一个低级整数“句柄”,用于在Linux和其他类Unix系统中识别内核级别的已打开文件(或套接字等)。
您将“裸”文件描述符传递给实际的Unix调用,例如read()
,write()
等。
FILE
指针是C标准库级构造,用于表示文件。 FILE
包装文件描述符,并添加缓冲和其他功能,使I / O更容易。
答案 1 :(得分:55)
一个是缓冲的(FILE *
)而另一个则不是。实际上,当你从“真实”文件(即驱动器上)读取时,你几乎总是想要使用FILE *
,除非你知道自己在做什么,或者除非你的文件实际上是一个套接字。
您可以使用FILE *
从fileno()
获取文件描述符,然后使用FILE *
fdopen()
答案 2 :(得分:17)
文件描述符只是一个从Posix'open()
调用中获得的整数。使用标准C fopen()
,您将获得FILE
结构。 FILE
结构包含此文件描述符以及其他内容,例如文件结束和错误指示符,流位置等。
因此,与fopen()
相比,使用open()
可以获得一定程度的抽象。通常,您应该使用fopen()
,因为它更易于移植,您可以使用所有其他使用FILE
结构的标准C函数,即fprintf()
和family。
使用或者没有性能问题。
答案 3 :(得分:12)
文件描述符与文件指针
文件描述符:
文件描述符是open()
系统调用返回的整数值。
int fd = open (filePath, mode);
文件指针:
文件指针是指向fopen()
库函数返回的C结构的指针,用于标识文件,包装文件描述符,缓冲功能以及I / O操作所需的所有其他功能。文件指针的类型为 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;
答案 4 :(得分:11)
想要添加可能有用的积分。
关于FILE *
我多次使用它来调试日志。 例如,
FILE *fp;
fp = fopen("debug.txt","a");
fprintf(fp,"I have reached till this point");
fclose(fp);
关于FILE DESCRIPTOR
它通常用于IPC。
对* nix系统上的文件(设备,文件,套接字等)进行低级别控制,因此比FILE *
更强大。
答案 5 :(得分:3)
FILE *
更有用,因为它允许您使用sprintf()
,sscanf()
,fgets()
等API函数, feof()
等。
文件描述符API是低级的,因此它允许使用套接字,管道,内存映射文件(当然还有常规文件)。
答案 6 :(得分:2)
请完成讨论(如果有兴趣)......
fopen
可能不安全,您应该使用fopen_s
或open
设置排他位。 C1X提供x
种模式,因此您可fopen
使用模式"rx"
,"wx"
等。
如果您使用open
,则可以考虑open(..., O_EXCL | O_RDONLY,... )
或open(..., O_CREAT | O_EXCL | O_WRONLY,... )
。
例如,请参阅Do not make assumptions about fopen() and file creation。
答案 7 :(得分:1)
系统调用主要使用文件描述符,例如read
和write
。库函数将使用文件指针(printf
,scanf
)。但是,库函数仅使用内部系统调用。
答案 8 :(得分:0)
我找到了一个不错的资源here,概述了两者之间的区别:
要对文件进行输入或输出时,可以选择两种基本机制来表示程序与文件之间的连接:文件描述符和流。文件描述符表示为int类型的对象,而流表示为FILE *对象。
文件描述符为输入和输出操作提供了原始的低级接口。文件描述符和流都可以表示与设备(例如终端)的连接,或者用于与另一个进程进行通信的管道或套接字以及普通文件的连接。但是,如果要执行特定于特定类型设备的控制操作,则必须使用文件描述符。没有任何设施可以通过这种方式使用流。如果程序需要以特殊模式进行输入或输出,例如非阻塞(或轮询)输入(请参阅文件状态标志),则还必须使用文件描述符。
流提供了一个更高层的接口,位于原始文件描述符功能之上。流接口对各种文件的处理非常相似,唯一的例外是可以选择的三种缓冲样式(请参见流缓冲)。
使用流接口的主要优点是,用于执行流的实际输入和输出操作(与控制操作相对)的功能集比文件描述符的相应功能更丰富,功能更强大。文件描述符接口仅提供用于传输字符块的简单功能,而流接口还提供了强大的格式化输入和输出功能(printf和scanf)以及面向字符和行的输入和输出功能。
由于流是根据文件描述符实现的,因此您可以从流中提取文件描述符,然后直接对文件描述符执行低级操作。您还可以首先以文件描述符的形式打开连接,然后创建与该文件描述符关联的流。
通常,您应该坚持使用流而不是文件描述符,除非您要执行某些特定操作,而该操作只能在文件描述符上完成。如果您是入门程序员,但不确定要使用哪些函数,建议您集中精力使用格式化的输入函数(请参见格式化输入)和格式化的输出函数(请参见格式化输出)。
如果您担心程序到GNU以外的系统的可移植性,则还应该注意文件描述符不像流那样可移植。您可以期望任何运行ISO C的系统都支持流,但是非GNU系统可能根本不支持文件描述符,或者只能实现对文件描述符进行操作的GNU函数的子集。但是,GNU C库中的大多数文件描述符函数都包含在POSIX.1标准中。