是否有任何理由(除了句法的)你想使用
FILE *fdopen(int fd, const char *mode);
或者
FILE *fopen(const char *path, const char *mode);
代替
int open(const char *pathname, int flags, mode_t mode);
在 Linux 环境中使用 C 时?
fdopen
和 open
还是 fopen
和 open
?
fopen
是标准 C 库的一部分,open
不是。编写可移植代码时使用 fopen
。
open
是一个 POSIX 函数。
首先,如果 fopen
是一个选项而 open
是另一个可能的选项,则没有特别好的理由使用 fdopen
。如果您想要 FILE *
,您一开始就不应该使用 open
打开文件。因此,在该列表中包含 fdopen
是不正确且令人困惑的,因为它与其他列表不太相似。我现在将继续忽略它,因为这里的重要区别在于 C 标准 FILE *
和特定于操作系统的文件描述符之间。
使用 fopen
而不是 open
有四个主要原因。
fopen 为您提供缓冲 IO,结果可能比您使用 open 所做的要快得多。如果文件没有以二进制模式打开,fopen 会进行行尾转换,如果您的程序曾经被移植到非 Unix 环境,这将非常有帮助(尽管世界似乎正在收敛于仅 LF(IETF 基于文本的除外)网络协议,如 SMTP 和 HTTP 等))。 FILE * 使您能够使用 fscanf 和其他 stdio 函数。您的代码可能有一天需要移植到其他仅支持 ANSI C 且不支持 open 函数的平台。
在我看来,行尾翻译更多地阻碍了你而不是帮助你,并且 fscanf
的解析非常弱,以至于你不可避免地最终将它扔掉以支持更有用的东西。
大多数支持 C 的平台都有 open
函数。
这就留下了缓冲问题。在您主要按顺序读取或写入文件的地方,缓冲支持确实很有帮助,并且大大提高了速度。但这可能会导致一些有趣的问题,即数据不会在您期望它存在时出现在文件中。您必须记住在适当的时候使用 fclose
或 fflush
。
如果您正在进行搜索(又名 fsetpos
或 fseek
,其中的第二个在符合标准的方式中使用会稍微复杂一些),缓冲的用处很快就会下降。
当然,我的偏见是我倾向于大量使用套接字,并且事实上您确实希望在没有缓冲的情况下进行非阻塞 IO(FILE *
完全无法以任何合理的方式支持)所有并且经常有复杂的解析要求真的影响了我的看法。
open()
是低级操作系统调用。 fdopen()
将 os 级别的文件描述符转换为 C 语言的更高级别的 FILE 抽象。 fopen()
在后台调用 open()
并直接为您提供一个 FILE 指针。
使用 FILE 对象而不是原始文件描述符有几个优点,其中包括更易于使用,还有其他技术优势,例如内置缓冲。特别是缓冲通常会带来相当大的性能优势。
fopen()
在打开文件时不提供相同级别的控制,例如创建权限、共享模式等。通常 open()
和变体提供更多控制,接近操作系统实际提供的控制
mmap
文件并使用普通 I/O 进行更改(听起来不可思议,我们在项目中确实这样做了,而且出于真正的充分理由),缓冲会成为障碍。
fopen vs 在 C 中打开
1) fopen
是库函数,而 open
是系统调用。
2) fopen
提供 缓冲 IO,与 非缓冲 的 open
相比,它更快。
3) fopen
便携,而 open
不便携(开放是特定于环境的)。
4) fopen
返回一个指向 FILE 结构(FILE *) 的指针; open
返回一个标识文件的整数。
5) FILE *
使您能够使用 fscanf 和其他 stdio 函数。
open
是 POSIX 标准,因此非常便携
fopen()
不是 async-signal-safe(缓冲的 io 都不是),因此不应在任何信号处理程序中使用它 - 或者在使用异步线程的函数中使用可能被它调用并小心处理的函数.使用 open()
会增加复杂性并错过缓冲 io,...
除非您属于 0.1% 的应用程序,在这些应用程序中使用 open
可以获得实际的性能优势,否则确实没有充分的理由不使用 fopen
。就 fdopen
而言,如果您不使用文件描述符,则不需要该调用。
坚持使用 fopen
及其方法系列(fwrite
、fread
、fprintf
等),您会非常满意。同样重要的是,其他程序员会对您的代码感到满意。
如果您有 FILE *
,则可以使用 fscanf
、fprintf
和 fgets
等函数。如果您只有文件描述符,则输入和输出例程有限(但可能更快)read
, write
等。
使用 open、read、write 意味着您必须担心信号交互。
如果调用被信号处理程序中断,函数将返回 -1 并将 errno 设置为 EINTR。
所以关闭文件的正确方法是
while (retval = close(fd), retval == -1 && ernno == EINTR) ;
close
,这取决于操作系统。在 Linux、AIX 和其他一些操作系统上做循环是不正确的。
SA_RESTART
而是让系统调用返回 EINTR
?
open()
是一个系统调用,特定于基于 Unix 的系统,它返回一个文件描述符。您可以使用 write()
写入文件描述符,它是另一个系统调用。
fopen()
是一个 ANSI C 函数调用,它返回一个文件指针,它可以移植到其他操作系统。我们可以使用 fprintf
写入文件指针。
在 Unix 中:您可以使用以下方法从文件描述符中获取文件指针:
fP = fdopen(fD, "a");
您可以使用以下方法从文件指针中获取文件描述符:
fD = fileno (fP);
我为我的应用程序从 fopen() 更改为 open(),因为每次运行 fopen fgetc 时 fopen 都会导致双重读取。双重阅读破坏了我试图完成的事情。 open() 似乎只是按照你的要求去做。
open() 将在每个 fopen() 系列函数的末尾调用。 open() 是系统调用, fopen() 由库作为包装函数提供,方便用户使用
还取决于打开所需的标志。关于写入和读取(以及可移植性)的使用,应使用 f*,如上所述。
但是,如果基本上想要指定的不仅仅是标准标志(如 rw 和附加标志),您将不得不使用特定于平台的 API(如 POSIX open)或抽象这些细节的库。 C 标准没有任何此类标志。
例如,您可能想要打开一个文件,只有当它退出时。如果您不指定创建标志,则该文件必须存在。如果你添加独占创建,它只会创建不存在的文件。还有很多。
例如,在 Linux 系统上,有一个通过 sysfs 公开的 LED 接口。它通过文件暴露了led的亮度。将数字写入或读取为 0-255 范围内的字符串。当然,您不想创建该文件,并且仅在它存在时才写入它。现在很酷的事情:使用 fdopen 使用标准调用来读/写这个文件。
使用 fopen 打开文件之前,我们可以从(到)磁盘上的文件读取(或写入)信息,我们必须打开文件。打开我们调用函数 fopen 的文件。
1.firstly it searches on the disk the file to be opened.
2.then it loads the file from the disk into a place in memory called buffer.
3.it sets up a character pointer that points to the first character of the buffer.
这种 fopen 函数的行为方式在缓冲过程中有一些原因,它可能会超时。所以在比较 fopen(high level i/o) 和 open(low level i/o) 系统调用时,它比 fopen 更快更合适。
不定期副业成功案例分享
fgets
,fgetc
,fscanf
,fread
) 读取,将始终读取缓冲区的整个大小(4K、8K 或您设置的任何内容)。通过使用直接 I/O,您可以避免这种情况。在这种情况下,最好使用pread
而不是查找/读取对(1 个系统调用而不是 2 个)。read()
和write()
调用是使用 libc 系列函数的第五个方便的原因。ioctl
的平台也支持fileno
调用,它接受一个FILE *
并返回一个可在ioctl
调用中使用的数字。不过要小心。FILE *
相关调用可能会与使用ioctl
更改有关底层文件描述符的某些内容令人惊讶地交互。