使用 open() 而不是 fopen() 有什么常见的理由吗?
在离开 C 很长一段时间后,我正在用 C 语言做一个小项目。 这些恰好包括一些文件处理。 我在各种文档中注意到有些函数返回 FILE * 句柄,而其他函数则返回(小整数)描述符。 两组功能都提供了我需要的相同的基本服务,所以我使用并不重要。
但我对集合智慧很好奇:使用 fopen()
和朋友更好,还是使用 open()
和朋友更好?
编辑 由于有人提到了缓冲与非缓冲以及访问设备,我应该补充一点,这个小项目的一部分将是在 FUSE 下编写用户空间文件系统驱动程序。 因此,文件级访问可以像在“文件”(即图像)上一样轻松地在设备(例如 CDROM 或 SCSI 驱动器)上进行。
I'm doing a small project in C after quite a long time away from it. These happen to include some file handling. I noticed in various documentation that there are functions which return FILE *
handles and others which return (small integer) descriptors. Both sets of functions offer the same basic services I need so it really does not matter I use.
But I'm curious about the collection wisdom: is it better to use fopen()
and friends, or open()
and friends?
Edit Since someone mentioned buffered vs unbuffered and accessing devices, I should add that one part of this small project will be writing a userspace filesystem driver under FUSE. So the file level access could as easily be on a device (e.g. a CDROM or a SCSI drive) as on a "file" (i.e. an image).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
如果您坚持使用类 UNIX 系统,并且您可能希望:
最好使用 fopen/fread/fwrite 以获得最大的可移植性,因为这些是标准 C 函数,而我上面提到的函数不是。
It is better to use open() if you are sticking to unix-like systems and you might like to:
It is better to use fopen/fread/fwrite for maximum portability, as these are standard C functions, the functions I've mentioned above aren't.
关于“fopen”是可移植的而“open”不是可移植的反对意见是虚假的。
fopen 是 libc 的一部分,open 是 POSIX 系统调用。
每一个都像它们来自的地方一样便携。
fopen'ed 文件的 i/o 是(您必须假设它可能是,并且出于实际目的,它是)由 libc 缓冲,文件描述符 open()'ed 不由 libc 缓冲(它们很可能是,并且通常是)缓冲在文件系统中——但并不是所有你打开的文件都是文件系统上的文件
,例如,像 /dev/sg0 或 /dev/tty0 这样的设备节点。你要做什么?你要对 FILE * 执行 ioctl?祝你好运。
也许你想用 O_DIRECT 之类的标志打开——对 fopen() 来说没有意义。
The objection that "fopen" is portable and "open" isn't is bogus.
fopen is part of libc, open is a POSIX system call.
Each is as portable as the place they come from.
i/o to fopen'ed files is (you must assume it may be, and for practical purposes, it is) buffered by libc, file descriptors open()'ed are not buffered by libc (they may well be, and usually are buffered in the filesystem -- but not everything you open() is a file on a filesystem.
What's the point of fopen'ing, for example, a device node like /dev/sg0, say, or /dev/tty0... What are you going to do? You're going to do an ioctl on a FILE *? Good luck with that.
Maybe you want to open with some flags like O_DIRECT -- makes no sense with fopen().
fopen 的工作级别比 open ....
fopen 返回一个指向 FILE 流的指针,类似于您在 C++ 中读取的流抽象
open 返回您打开的文件的文件描述符...它不为您提供流抽象,您负责处理位和自己的字节...与 fopen 相比,这是一个较低的级别
Stdio 流被缓冲,而 open() 文件描述符则没有。 取决于你需要什么。 您还可以从另一个创建一个:
int fileno (FILE * stream) 返回 FILE * 的文件描述符,FILE * fdopen(int fildes, const char * mode) 从文件描述符创建 FILE * 。
混合缓冲和非缓冲 IO 时要小心,因为当您不使用 fflush() 刷新缓冲区时,您将丢失缓冲区中的内容。
fopen works at a higher level than open ....
fopen returns you a pointer to FILE stream which is similar to the stream abstraction that you read in C++
open returns you a file descriptor for the file opened ... It does not provide you a stream abstraction and you are responsible for handling the bits and bytes yourself ... This is at a lower level as compared to fopen
Stdio streams are buffered, while open() file descriptors are not. Depends on what you need. You can also create one from the other:
int fileno (FILE * stream) returns the file descriptor for a FILE *, FILE * fdopen(int fildes, const char * mode) creates a FILE * from a file descriptor.
Be careful when intermixing buffered and non-buffered IO, since you'll lose what's in your buffer when you don't flush it with fflush().
是的。 当您需要低级手柄时。
在 UNIX 操作系统上,通常可以交换文件句柄和套接字。
此外,低级句柄比 FILE 指针具有更好的 ABI 兼容性。
Yes. When you need a low-level handle.
On UNIX operating systems, you can generally exchange file handles and sockets.
Also, low-level handles make for better ABI compatibility than FILE pointers.
read() & write() 使用无缓冲 I/O。 (fd:整数文件描述符)
fread() & fwrite() 使用缓冲 I/O。 (FILE* 结构指针)
使用 write() 写入管道的二进制数据可能不会< /strong> 能够使用 fread() 读取二进制数据,因为字节对齐、可变大小等。这是一个废话。
大多数低级设备驱动程序代码使用无缓冲的 I/O 调用。
大多数应用程序级 I/O 使用缓冲。
使用FILE*及其相关函数
在逐台机器的基础上是可以的:但是失去了可移植性
在其他架构上读取和写入二进制数据。
fwrite() 是缓冲 I/O,如果出现以下情况,可能会导致不可靠的结果:
为 64 位架构编写并在 32 位上运行; 或(Windows/Linux)。
大多数操作系统在自己的代码中都有兼容性宏来防止这种情况发生。
对于低级二进制 I/O 可移植性 read() 和 write() 保证
在不同的体系结构上编译时,相同的二进制文件会读取和写入。
基本的事情是选择一种方式或另一种方式并保持一致,
整个二进制套件。
因此,对于基本用途,我个人会使用上述内容,而不会过多地混合习惯用法。
相比之下,
这些提供了对读取和写入字节的细粒度控制
(推荐用于特殊设备和 fifos(管道))。
再次强调,使用你需要的东西,但保持习惯用法和界面的一致。
如果你的大部分代码库使用一种模式,也使用它,除非有
一个不这样做的真正原因。 两组I/O库函数都极其可靠
并每天使用数百万次。
注意--如果您正在将 CI/O 与另一种语言连接,
(perl、python、java、c#、lua ...)查看这些语言的开发人员
在编写 C 代码之前建议您这样做,这样可以省去一些麻烦。
read() & write() use unbuffered I/O. (fd: integer file descriptor)
fread() & fwrite() use buffered I/O. (FILE* structure pointer)
Binary data written to a pipe with write() may not be able to read binary data with fread(), because of byte alignments, variable sizes, etc. Its a crap-shoot.
Most low-level device driver code uses unbuffered I/O calls.
Most application level I/O uses buffered.
Use of the FILE* and its associated functions
is OK on a machine-by-machine basis: but portability is lost
on other architectures in the reading and writing of binary data.
fwrite() is buffered I/O and can lead to unreliable results if
written for a 64 bit architecture and run on a 32bit; or (Windows/Linux).
Most OSs have compatibility macros within their own code to prevent this.
For low-level binary I/O portability read() and write() guarantee
the same binary reads and writes when compiled on differing architectures.
The basic thing is to pick one way or the other and be consistent about it,
throughout the binary suite.
So for basic use I would personally use the above without mixing idioms too much.
By contrast,
These provide fine-grained control over reading and writing bytes
(recommended for special devices and fifos (pipes) ).
So again, use what you need, but keep consistent in your idioms and interfaces.
If most of your code base uses one mode , use that too, unless there is
a real reason not to. Both sets of I/O library functions are extremely reliable
and used millions of times a day.
note-- If you are interfacing C I/O with another language,
(perl, python, java, c#, lua ...) check out what the developers of those languages
recommend before you write your C code and save yourself some trouble.
通常,您应该倾向于使用标准库(fopen)。 但是,有些情况下您需要直接使用 open。
我想到的一个例子是解决旧版本 solaris 中的一个错误,该错误导致 fopen 在打开 256 个文件后失败。 这是因为他们在 struct FILE 实现中错误地使用了 unsigned char 作为 fd 字段,而不是 int。 但这是一个非常具体的案例。
usually, you should favor using the standard library (fopen). However, there are occasions where you will need to use open directly.
One example that comes to mind is to work around a bug in an older version of solaris which made fopen fail after 256 files were open. This was because they erroniously used an unsigned char for the fd field in their struct FILE implementation instead of an int. But this was a very specific case.
fopen 和它的表兄弟是缓冲的。 打开、读取和写入不会被缓冲。 您的应用程序可能会或可能不会关心。
fprintf 和 scanf 有更丰富的 API,允许您读取和写入格式化文本文件。 读取和写入使用基本的字节数组。 转换和格式必须手工制作。
文件描述符和 (FILE *) 之间的区别实际上是无关紧要的。
兰迪
fopen and its cousins are buffered. open, read, and write are not buffered. Your application may or may not care.
fprintf and scanf have a richer API that allows you to read and write formatted text files. read and write use fundamental arrays of bytes. Conversions and formatting must be hand crafted.
The difference between file descriptors and (FILE *) is really inconsequential.
Randy