是否有任何普通的理由使用open()而不是fopen()?

时间:2009-02-13 04:03:26

标签: c file posix libc

经过相当长的一段时间后,我正在用C做一个小项目。这些碰巧包括一些文件处理。我在各种文档中注意到有返回FILE *句柄的函数和返回(小整数)描述符的其他函数。这两组功能都提供了我需要的相同基本服务,所以我使用它并不重要。

但我对收藏智慧感到好奇:使用fopen()和朋友,或open()和朋友是否更好?

编辑由于有人提到缓冲与未缓冲和访问设备,我应该补充说,这个小项目的一部分将在FUSE下编写用户空间文件系统驱动程序。因此,文件级访问可以像在“文件”(即图像)上一样轻松地在设备(例如CDROM或SCSI驱动器)上。

7 个答案:

答案 0 :(得分:14)

如果您坚持使用类似unix的系统,最好使用open()并且您可能希望:

  • 在创建文件时对unix权限位进行更细粒度的控制。
  • 使用较低级别的功能,例如read / write / mmap,而不是C缓冲流I / O功能。
  • 使用基于文件描述符(fd)的IO调度(轮询,选择等)您当然可以使用fileno()从FILE *获取fd,但必须注意不要将基于FILE *的流函数与基于fd的功能。
  • 打开任何特殊设备(不是常规文件)

最好使用fopen / fread / fwrite来获得最大的可移植性,因为这些是标准的C函数,我上面提到的函数不是。

答案 1 :(得分:6)

“fopen”是便携式和“开放式”的反对意见不是假的。

fopen是libc的一部分,open是POSIX系统调用。

每个都像他们来自的地方一样便携。

对于fopen'ed文件的i / o是(你必须假设它可能是,并且出于实际目的,它是)由libc缓冲,文件描述符open()'ed不被libc缓冲(它们可能是,并且通常在文件系统中缓冲 - 但不是你打开的所有东西()都是文件系统上的文件。

fopen的意思是什么,例如,像/ dev / sg0这样的设备节点,比如说,或者/ dev / tty0 ......你打算做什么?你要在FILE上做一个ioctl *?祝你好运。

也许你想打开一些像O_DIRECT这样的标志 - 对fopen()毫无意义。

答案 2 :(得分:4)

fopen的工作水平高于开放.... fopen返回一个指向FILE流的指针,它类似于你在C ++中读取的流抽象

open返回一个打开文件的文件描述符...它没有为你提供流抽象,你自己负责处理比特和字节......与fopen相比,这是一个较低的级别

Stdio流是缓冲的,而open()文件描述符则不是。取决于你需要什么。您也可以从另一个创建一个:

int fileno(FILE * stream)返回FILE *的文件描述符,FILE * fdopen(int fildes,const char * mode)从文件描述符创建FILE *。

在混合缓冲和非缓冲IO时要小心,因为当你不用fflush()冲洗它时,你会丢失缓冲区中的内容。

答案 3 :(得分:3)

是。当你需要一个低级句柄时。

在UNIX操作系统上,通常可以交换文件句柄和套接字。

此外,低级句柄比FILE指针具有更好的ABI兼容性。

答案 4 :(得分:2)

通常,您应该支持使用标准库(fopen)。但是,有时您需要直接使用open。

我想到的一个例子是解决旧版本solaris中的一个错误,该错误导致256个文件打开后fopen失败。这是因为他们在struct FILE实现中使用unsigned char作为fd字段而不是int。但这是一个非常具体的案例。

答案 5 :(得分:2)

read()& write()使用无缓冲的I / O. ( fd :整数文件描述符)

fread()& fwrite()使用缓冲I / O. ( FILE * 结构指针)

使用 write() 写入管道的二进制数据可能 能够使用 fread()<读取二进制数据/ em>,因为字节对齐,可变大小等等。这是一个废话。

大多数低级设备驱动程序代码使用无缓冲的I / O调用。

大多数应用程序级I / O都使用缓冲。

使用 FILE *及其相关功能 在逐个机器的基础上是可以的:但是可移植性丢失了 在其他体系结构中读取和写入二进制数据。 fwrite()是缓冲I / O,如果导致不可靠的结果 为64位架构编写并运行在32位;或(Windows / Linux)。 大多数操作系统在自己的代码中都有兼容性宏来防止这种情况发生。

对于低级二进制I / O可移植性 read() write()保证 在不同的体系结构上编译时,相同的二进制读写。 基本的事情是选择一种方式,并保持一致, 整个二进制套件。

<stdio.h>  // mostly FILE*  some fd input/output parameters for compatibility
             // gives you a lot of helper functions -->
List of Functions
       Function      Description
       ───────────────────────────────────────────────────────────────────
       clearerr      check and reset stream status
       fclose        close a stream
       fdopen        stream open functions //( fd argument, returns FILE*)                      feof          check and reset stream status
       ferror        check and reset stream status
       fflush        flush a stream
       fgetc         get next character or word from input stream
       fgetpos       reposition a stream
       fgets         get a line from a stream
       fileno        get file descriptor   // (FILE* argument, returns fd) 
       fopen         stream open functions
       fprintf       formatted output conversion
       fpurge        flush a stream
       fputc         output a character or word to a stream
       fputs         output a line to a stream
       fread         binary stream input/output
       freopen       stream open functions
       fscanf        input format conversion
       fseek         reposition a stream
       fsetpos       reposition a stream
       ftell         reposition a stream
       fwrite        binary stream input/output
       getc          get next character or word from input stream
       getchar       get next character or word from input stream
       gets          get a line from a stream
       getw          get next character or word from input stream
       mktemp        make temporary filename (unique)
       perror        system error messages
       printf        formatted output conversion
       putc          output a character or word to a stream
       putchar       output a character or word to a stream
       puts          output a line to a stream
       putw          output a character or word to a stream
       remove        remove directory entry
       rewind        reposition a stream
       scanf         input format conversion
       setbuf        stream buffering operations
       setbuffer     stream buffering operations
       setlinebuf    stream buffering operations
       setvbuf       stream buffering operations
       sprintf       formatted output conversion
       sscanf        input format conversion
       strerror      system error messages
       sys_errlist   system error messages
       sys_nerr      system error messages
       tempnam       temporary file routines
       tmpfile       temporary file routines
       tmpnam        temporary file routines
       ungetc        un-get character from input stream
       vfprintf      formatted output conversion
       vfscanf       input format conversion
       vprintf       formatted output conversion
       vscanf        input format conversion
       vsprintf      formatted output conversion
       vsscanf       input format conversion

因此,对于基本用途,我个人会使用上述内容而不会过多地混淆习语。

相比之下,

<unistd.h>   write()
             lseek()
             close()
             pipe()
<sys/types.h>
<sys/stat.h>
<fcntl.h>  open()
           creat()
           fcntl() 
all use file descriptors.

这些提供了对读写字节的细粒度控制 (推荐用于特殊设备和fifos(管道))。

再次,使用你需要的东西,但在你的习语和界面中保持一致。 如果你的大部分代码库都使用一种模式,那么也要使用它,除非有 一个真正的理由不去。两组I / O库函数都非常可靠 并且每天使用数百万次。

note - 如果您正在使用其他语言连接C I / O, (perl,python,java,c#,lua ...)签出这些语言的开发者是什么 在编写C代码之前建议并省去一些麻烦。

答案 6 :(得分:0)

fopen和它的表兄弟都是缓冲的。打开,读取和写入都不是缓冲的。您的申请可能会或可能不会关心。

fprintf和scanf有一个更丰富的API,允许您读取和写入格式化的文本文件。读写使用基本的字节数组。转换和格式化必须手工制作。

文件描述符和(FILE *)之间的区别实际上是无关紧要的。

兰迪