C fopen vs open

Posted

技术标签:

【中文标题】C fopen vs open【英文标题】: 【发布时间】:2010-12-12 02:57:15 【问题描述】:

你有什么理由(除了句法的)你想使用

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 时?

【问题讨论】:

您的意思是fdopenopen 还是fopenopen 你说的不是 fopen,不是 fdopen? fopen 是标准 C 库的一部分,open 不是。编写可移植代码时使用fopen 是的,我的意思是 fopen。我刚刚更新了它,但我认为同样的原则也适用。 @Aziz, open 是一个 POSIX 函数。 【参考方案1】:

首先,如果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 函数。

这就留下了缓冲问题。在您主要按顺序读取或写入文件的地方,缓冲支持确实很有帮助并且大大提高了速度。但它可能会导致一些有趣的问题,即数据不会在您期望它存在时出现在文件中。你必须记得在适当的时候fclosefflush

如果您正在进行搜索(又名 fsetposfseek,其中的第二个在符合标准的情况下使用起来稍微麻烦一些),缓冲的用处很快就会下降。

当然,我的偏见是我经常使用套接字,而且事实上你真的想要做非阻塞 IO(FILE * 完全无法以任何合理的方式支持)根本没有缓冲,而且经常有复杂的解析要求,这确实影响了我的看法。

【讨论】:

我不会质疑您的经历,但我很想听听您对此进行详细说明。对于什么样的应用程序,您觉得内置缓冲会妨碍您吗?究竟是什么问题? 没看到最后一段。有效点,恕我直言。不过,据我所知,问题是关于文件 IO。 澄清缓冲何时妨碍。这是你使用搜索的时候。以下使用任何命令 (fgets, fgetc, fscanf, fread) 读取,将始终读取缓冲区的整个大小(4K、8K 或您设置的任何内容)。通过使用直接 I/O,您可以避免这种情况。在这种情况下,最好使用 pread 而不是查找/读取对(1 个系统调用而不是 2 个)。 处理中断的read()write() 调用是使用libc 系列函数的第五个方便的理由。 @m-ric:嗯,这是一个有点不相关的问题,但是是的。所有支持ioctl 的平台也支持fileno 调用,它接受FILE * 并返回一个可在ioctl 调用中使用的数字。不过要小心。 FILE * 相关调用可能会与使用 ioctl 更改有关底层文件描述符的某些内容令人惊讶地交互。【参考方案2】:

open() 是一个低级的操作系统调用。 fdopen() 将 os 级别的文件描述符转换为 C 语言的更高级别的 FILE 抽象。 fopen() 在后台调用open() 并直接给你一个文件指针。

使用 FILE 对象而不是原始文件描述符有几个优点,其中包括更易于使用,还有其他技术优势,例如内置缓冲。尤其是缓冲通常会带来相当大的性能优势。

【讨论】:

使用缓冲的 'f...' 版本的 open 有什么缺点吗? @L. Moser,是的,当您已经在缓冲数据时,因此额外的缓冲区会增加不必要的复制和内存开销。 其实还有其他的缺点。 fopen() 在打开文件时不提供相同级别的控制,例如创建权限、共享模式等。通常open() 和变体提供更多控制,接近操作系统实际提供的控制 还有一些极端情况,你 mmap 文件并使用普通 I/O 进行更改(听起来令人难以置信,我们在项目中确实这样做了,并且有充分的理由),缓冲会碍事的。 您可能还想使用其他系统函数,例如使用 open() 通过 readahead() 将文件预加载到页面缓存中。我猜经验法则是“使用 fopen,除非你绝对需要 open()”,open() 实际上可以让你做一些花哨的事情(设置/不设置 O_ATIME 和类似的)。【参考方案3】:

fopen 与在 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,...【参考方案4】:

除非您属于 0.1% 的应用程序,使用 open 会带来实际的性能优势,否则确实没有充分的理由不使用 fopen。就fdopen 而言,如果您不使用文件描述符,则不需要该调用。

坚持使用fopen 及其一系列方法(fwritefreadfprintf 等),您会非常满意。同样重要的是,其他程序员会对您的代码感到满意。

【讨论】:

【参考方案5】:

如果您有FILE *,您可以使用fscanffprintffgets 等函数。如果您只有文件描述符,则输入和输出例程有限(但可能更快)@ 987654325@、write

【讨论】:

【参考方案6】:

使用 open、read、write 意味着您必须担心信号交互。

如果调用被信号处理程序中断,函数将返回 -1 并将 errno 设置为 EINTR。

所以关闭文件的正确方法是

while (retval = close(fd), retval == -1 && ernno == EINTR) ;

【讨论】:

对于close,这取决于操作系统。在 Linux、AIX 和其他一些操作系统上做循环是不正确的。 另外,使用 read 和 write 也会遇到同样的问题,即它们可能在完全处理输入/输出之前被信号中断,程序员必须处理这种情况,而 fread 和 fwrite很好地处理信号中断。【参考方案7】:

open() 是一个系统调用,特定于基于 Unix 的系统,它返回一个文件描述符。您可以使用 write() 写入文件描述符,这是另一个系统调用。fopen() 是一个 ANSI C 函数调用,它返回一个文件指针,它可以移植到其他操作系统。我们可以使用fprintf 写入文件指针。

在 Unix 中: 您可以使用以下方法从文件描述符中获取文件指针:

fP = fdopen(fD, "a");

您可以使用以下方法从文件指针中获取文件描述符:

fD = fileno (fP);

【讨论】:

【参考方案8】:

open() 将在每个 fopen() 系列函数的末尾调用。 open() 是系统调用,fopen() 由库提供作为包装函数,方便用户使用

【讨论】:

【参考方案9】:

我为我的应用程序从 fopen() 更改为 open(),因为每次运行 fopen fgetc 时 fopen 都会导致双重读取。双重阅读破坏了我试图完成的工作。 open() 似乎只是按照你的要求去做。

【讨论】:

【参考方案10】:

还取决于打开所需的标志。关于书写和阅读的使用(以及可移植性),应该使用 f*,如上所述。

但如果基本上想要指定的不仅仅是标准标志(如 rw 和附加标志),您将不得不使用特定于平台的 API(如 POSIX open)或抽象这些细节的库。 C 标准没有任何此类标志。

例如,您可能想要打开一个文件,但前提是它退出了。如果您不指定创建标志,则该文件必须存在。如果你添加独占创建,它只会创建不存在的文件。还有很多。

例如在 Linux 系统上有一个通过 sysfs 暴露的 LED 接口。它通过文件暴露了led的亮度。将数字写入或读取为 0-255 范围内的字符串。当然,您不想创建该文件,并且仅在它存在时才写入它。现在很酷的事情:使用 fdopen 通过标准调用来读/写这个文件。

【讨论】:

【参考方案11】:

使用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。

【讨论】:

打开速度比 fopen 快吗? 是的,open 是系统调用,比 fopen 快 - 比较@obayhan

以上是关于C fopen vs open的主要内容,如果未能解决你的问题,请参考以下文章

vs2015使用fopen时遇到unsafe问题

fopen vs access vs stat

fopen vs access vs stat

VS中fopen_s函数的用法(fopen函数的扩展)

C-读写文件和输出输出

如何用VS进行程序调试