经过相当长的一段时间后,我正在用C做一个小项目。这些碰巧包括一些文件处理。我在各种文档中注意到有返回FILE *
句柄的函数和返回(小整数)描述符的其他函数。这两组功能都提供了我需要的相同基本服务,所以我使用它并不重要。
但我对收藏智慧感到好奇:使用fopen()
和朋友,或open()
和朋友是否更好?
编辑由于有人提到缓冲与未缓冲和访问设备,我应该补充说,这个小项目的一部分将在FUSE下编写用户空间文件系统驱动程序。因此,文件级访问可以像在“文件”(即图像)上一样轻松地在设备(例如CDROM或SCSI驱动器)上。
答案 0 :(得分:14)
如果您坚持使用类似unix的系统,最好使用open()并且您可能希望:
最好使用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 *)之间的区别实际上是无关紧要的。
兰迪