C fopen vs open
Solution 1
First, there is no particularly good reason to use fdopen
if fopen
is an option and open
is the other possible choice. You shouldn't have used open
to open the file in the first place if you want a FILE *
. So including fdopen
in that list is incorrect and confusing because it isn't very much like the others. I will now proceed to ignore it because the important distinction here is between a C standard FILE *
and an OS-specific file descriptor.
There are four main reasons to use fopen
instead of open
.
-
fopen
provides you with buffering IO that may turn out to be a lot faster than what you're doing withopen
. -
fopen
does line ending translation if the file is not opened in binary mode, which can be very helpful if your program is ever ported to a non-Unix environment (though the world appears to be converging on LF-only (except IETF text-based networking protocols like SMTP and HTTP and such)). - A
FILE *
gives you the ability to usefscanf
and other stdio functions. - Your code may someday need to be ported to some other platform that only supports ANSI C and does not support the
open
function.
In my opinion the line ending translation more often gets in your way than helps you, and the parsing of fscanf
is so weak that you inevitably end up tossing it out in favor of something more useful.
And most platforms that support C have an open
function.
That leaves the buffering question. In places where you are mainly reading or writing a file sequentially, the buffering support is really helpful and a big speed improvement. But it can lead to some interesting problems in which data does not end up in the file when you expect it to be there. You have to remember to fclose
or fflush
at the appropriate times.
If you're doing seeks (aka fsetpos
or fseek
the second of which is slightly trickier to use in a standards compliant way), the usefulness of buffering quickly goes down.
Of course, my bias is that I tend to work with sockets a whole lot, and there the fact that you really want to be doing non-blocking IO (which FILE *
totally fails to support in any reasonable way) with no buffering at all and often have complex parsing requirements really color my perceptions.
Solution 2
open()
is a low-level os call. fdopen()
converts an os-level file descriptor to the higher-level FILE-abstraction of the C language. fopen()
calls open()
in the background and gives you a FILE-pointer directly.
There are several advantages to using FILE-objects rather raw file descriptors, which includes greater ease of usage but also other technical advantages such as built-in buffering. Especially the buffering generally results in a sizeable performance advantage.
Solution 3
fopen vs open in C
1) fopen
is a library function while open
is a system call.
2) fopen
provides buffered IO which is faster compare to open
which is non buffered.
3) fopen
is portable while open
not portable (open is environment specific).
4) fopen
returns a pointer to a FILE structure(FILE *); open
returns an integer that identifies the file.
5) A FILE *
gives you the ability to use fscanf and other stdio functions.
Solution 4
Unless you're part of the 0.1% of applications where using open
is an actual performance benefit, there really is no good reason not to use fopen
. As far as fdopen
is concerned, if you aren't playing with file descriptors, you don't need that call.
Stick with fopen
and its family of methods (fwrite
, fread
, fprintf
, et al) and you'll be very satisfied. Just as importantly, other programmers will be satisfied with your code.
Solution 5
If you have a FILE *
, you can use functions like fscanf
, fprintf
and fgets
etc. If you have just the file descriptor, you have limited (but likely faster) input and output routines read
, write
etc.
Related videos on Youtube
LJM
Updated on January 25, 2022Comments
-
LJM over 2 years
Is there any reason (other than syntactic ones) that you'd want to use
FILE *fdopen(int fd, const char *mode);
or
FILE *fopen(const char *path, const char *mode);
instead of
int open(const char *pathname, int flags, mode_t mode);
when using C in a Linux environment?
-
Sam over 14 yearsDid you mean
fdopen
andopen
orfopen
andopen
? -
Omnifarious over 14 yearsDon't you mean fopen, not fdopen?
-
Aziz over 14 years
fopen
is part of standard C library,open
is not. Usefopen
when writing portable code. -
LJM over 14 yearsYes, I meant fopen. I just updated it, but I think the same principle applies.
-
TOMKA over 14 years@Aziz,
open
is a POSIX function though. -
SamB almost 13 yearsAmusing tidbit: this just came up when I searched for "open function C" on the MSDN site :-)
-
Jonathan Leffler about 5 yearsIf you have a file descriptor created by
pipe()
— or perhapssocket()
, though that's less likely — and you want to use standardFILE *
I/O on it, then you need to usefdopen()
to create the stream. There are also numerous options that can be specified withopen()
that cannot be specified withfopen()
— perhaps most prominentlyO_EXCL
, but there are certainly others too — and those might be good reasons for usingopen()
(instead offopen()
) followed byfdopen()
. -
jw_ over 4 yearsfopen uses open too: FILE* fopen(const char* file, const char* mode) {... int fd = open(file, mode_flags, DEFFILEMODE);...FILE* fp = __fopen(fd, flags);...return fp;} where __fopen creates a FILE object using __sfp() and put the fd in it. BTW does anybody know where is __sfp()?
-
Admin about 2 years@dreamlax in current year, Linux is still not POSIX, nor UNIX, and from my limited knowledge, that's most popular kernel related to these, which I'd say, makes it pretty unportable, even if in case of POSIX, pretty much every system will have
open
...
-
-
LJM over 14 yearsAre there any disadvantages to using the buffered 'f...' versions of open?
-
Emil H over 14 yearsI'm not going to question your experiences, but I'd love to hear you elaborate a bit on this. For what kind of applications do you feel that the built-in buffering gets in the way? What exactly is the problem?
-
Emil H over 14 yearsDidn't see the last paragraph. Valid point, IMHO. As far as I can tell the question was about file IO, though.
-
Omnifarious over 14 yearsAlmost any program that does not stream IO, where you end up doing seeks into the middle of the file. I should update my response to clarify.
-
LJM over 14 yearsSo would it be correct to conclude that 'fgets' would block the thread until it reads a full line. And that non-buffered IO (such as read) would inherently not block the thread because they have no buffer to hold the data?
-
Omnifarious over 14 years@L. Moser: No. The blocking and buffering are not strongly coupled. You would have to set the file descriptor to
O_NONBLOCK
withfcntl
and and theEAGAIN
error whenread
failed in order to avoid blocking a thread withread
. -
Michael Aaron Safyan over 14 years@L. Moser, yes, when you are already buffering the data, and hence the additional buffer adds unnecessary copying and memory overhead.
-
Matt Joiner over 14 yearsactually there are other disadvantages.
fopen()
does not provide the same level of control when opening files, for example create permissions, sharing modes, and more. typicallyopen()
and variants provide much more control, close to what the operating system actually provides -
Jarosław Bielawski almost 14 yearsTo clarify when buffering gets in the way. It's when you use seek. The following read with whatever command (
fgets
,fgetc
,fscanf
,fread
) , will always read the whole size of the buffer (4K, 8K or whatever you set). By using the direct I/O you can avoid that. In that case it's even better to usepread
instead of a seek/read pair (1 syscall instead of 2). -
Jarosław Bielawski almost 14 yearsThere are also the extreme cases where you
mmap
the file and do changes with normal I/O (as incredible as it sounds we do actually that in our project and for real good reasons), buffering would be in the way. -
Omnifarious over 11 years@LJM - To clarify further on that somewhat muddled answer from 2 years ago... :-) Yes, fgets will do exactly that. And there is no reasonable way for it not to. But just using
read
does not magically get you non-blocking IO. You have to set the O_NONBLOCK flag on the descriptor somehow, and then properly handle the EAGAIN condition/error onread
. The latter, in particular, is non-trivial since you frequently need to remember some sort of parser state until there is data available toread
. Some people think you should just give up and use cheap threads that block. -
nccc over 11 yearsHandling interrupted
read()
andwrite()
calls is a convenient fifth reason to use the libc family of functions. -
m-ric over 11 yearsWhat about opening a device file and send an ioctl? Can I use
fopen
which returnsFILE*
where ioctl() expects andint fd
? -
Omnifarious over 11 years@m-ric: Well, that's a somewhat unrelated question, but yes. All platforms that support
ioctl
also support thefileno
call which takes aFILE *
and returns a number that can be used in anioctl
call. Be careful though.FILE *
related calls may interact surprisingly with usingioctl
to change something about the underlying file descriptor. -
Tomas Pruzina almost 11 yearsYou also may want to use other system functions, like using open() for preloading files into page cache via readahead(). I guess rule of thumb is "use fopen unless you absolutely need open()", open() actually lets you do fancy stuff (setting/not setting O_ATIME and similar).
-
strcat over 10 yearsFor
close
, this depends on the operating system. It's incorrect to do the loop on Linux, AIX and some other operating systems. -
Graham Asher about 9 yearsI own a map rendering library (CartoType) which does its own buffering. I experimented with moving from high-level to low-level io (from fopen to open, etc.) and benchmarked the performance before and after. Low-level io was better, but only by 3%. I have not yet decided whether a 3% improvement is worth it. Probably yes, because I can encapsulate the platform-dependent code.
-
obayhan over 7 yearsis open faster than fopen?
-
prashad about 7 yearsyes ,open is the system call, which is faster than fopen - comparitively @obayhan
-
osvein over 6 years
open
is a POSIX standard, so it's quite portable -
Marcelo almost 6 yearsIn addition, using read and write will suffer the same issue, i.e., they can get interrupted by a signal before processing the input/output entirely and the programmer has to handle such situations, while fread and fwrite handle signal interruptions nicely.
-
tav over 5 yearsThe second reason is rather doubtful because: For portability, it is strongly recommended that you always use the 'b' flag when opening files with fopen(). I strongly believe that the same code should produce binary equal files regardless of the operation system on which it is executed. Otherwise this code is not truly portable. And I do not see any problems when using Unix line endings everywhere because all significant applications on Windows (even Notepad since the last year) are support them.
-
Omnifarious over 5 years@tav - I happen to know that there is some pressure from the top at Microsoft to abandon CRLF line endings in Microsoft products in general. So, I expect them to slowly fade out.
-
Simon Sobisch almost 3 years
fopen()
is not async-signal-safe (none of the buffered io is), therefore it should not be used in any signal handler - or a function that may be called by it and be taken with care if used in functions that use asynchronous threads. Usingopen()
adds complexity and misses the buffered-io, ... -
Admin about 2 yearsI've seen this way too many times, but never a good reason why this would ever be issue. Maybe you could provide an example where it would actually be a necessity to not use
SA_RESTART
in your signal handler and instead have syscalls returnEINTR
? -
Jiminion about 2 years@osvein Not really portable anymore. Works fine with Linuxes, but is now deprecated in Windows. You are supposed to use _open, _close now. Sort of a minor point. I guess the headers needed on Linux and Windows are also different. I think it would be hard to write portable code without some "#if OS_LINUX" lines in it.