275

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?

UpAndAdam
  • 4,515
  • 3
  • 28
  • 46
LJM
  • 6,284
  • 7
  • 28
  • 30
  • 12
    `fopen` is part of standard C library, `open` is not. Use `fopen` when writing portable code. – Aziz Nov 01 '09 at 21:53
  • 9
    @Aziz, `open` is a POSIX function though. – dreamlax Nov 01 '09 at 21:55
  • If you have a file descriptor created by `pipe()` — or perhaps `socket()`, though that's less likely — and you want to use standard `FILE *` I/O on it, then you need to use `fdopen()` to create the stream. There are also numerous options that can be specified with `open()` that cannot be specified with `fopen()` — perhaps most prominently `O_EXCL`, but there are certainly others too — and those might be good reasons for using `open()` (instead of `fopen()`) followed by `fdopen()`. – Jonathan Leffler Mar 21 '19 at 04:24

11 Answers11

292

Of those, fdopen is not like the others. fdopen is what you would use if you first called open and then wanted a FILE *. There is no sense doing that if you have the choice to just call fopen instead. There are cases where you won't be able to get fopen to do exactly what you want, but they're outside the scope of this question.

So, let's just pretend fdopen isn't even there and get on with the question.

There are four main reasons to use fopen instead of open.

  1. fopen provides you with buffering IO that may turn out to be a lot faster than what you're doing with open.
  2. 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)).
  3. A FILE * gives you the ability to use fscanf and other stdio functions.
  4. 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 (and experience) 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.

Omnifarious
  • 54,333
  • 19
  • 131
  • 194
  • Almost 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. – Omnifarious Nov 01 '09 at 22:08
  • So 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? – LJM Nov 01 '09 at 22:14
  • @L. Moser: No. The blocking and buffering are not strongly coupled. You would have to set the file descriptor to `O_NONBLOCK` with `fcntl` and and the `EAGAIN` error when `read` failed in order to avoid blocking a thread with `read`. – Omnifarious Nov 01 '09 at 22:17
  • 11
    To 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 use `pread` instead of a seek/read pair (1 syscall instead of 2). – Patrick Schlüter May 05 '10 at 13:16
  • @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 on `read`. The latter, in particular, is non-trivial since you frequently need to remember some sort of parser state until there is data available to `read`. Some people think you should just give up and use cheap threads that block. – Omnifarious Aug 14 '12 at 04:13
  • 2
    Handling interrupted `read()` and `write()` calls is a convenient fifth reason to use the libc family of functions. – nccc Aug 26 '12 at 21:54
  • What about opening a device file and send an ioctl? Can I use `fopen` which returns `FILE*` where ioctl() expects and `int fd`? – m-ric Sep 28 '12 at 15:37
  • 4
    @m-ric: Well, that's a somewhat unrelated question, but yes. All platforms that support `ioctl` also support the `fileno` call which takes a `FILE *` and returns a number that can be used in an `ioctl` call. Be careful though. `FILE *` related calls may interact surprisingly with using `ioctl` to change something about the underlying file descriptor. – Omnifarious Sep 28 '12 at 15:53
  • 1
    I 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. – Graham Asher Apr 12 '15 at 15:45
  • The second reason is rather doubtful because: [For portability, it is strongly recommended that you always use the 'b' flag when opening files with fopen().](http://php.net/manual/en/function.fopen.php) 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](http://archive.li/Dskp0)) are support them. – tav Jan 27 '19 at 07:41
  • @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. – Omnifarious Jan 27 '19 at 17:11
76

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.

Emil H
  • 39,840
  • 10
  • 78
  • 97
  • 6
    Are there any disadvantages to using the buffered 'f...' versions of open? – LJM Nov 01 '09 at 21:58
  • 10
    @L. Moser, yes, when you are already buffering the data, and hence the additional buffer adds unnecessary copying and memory overhead. – Michael Aaron Safyan Nov 02 '09 at 01:41
  • 11
    actually there are other disadvantages. `fopen()` does not provide the same level of control when opening files, for example create permissions, sharing modes, and more. typically `open()` and variants provide much more control, close to what the operating system actually provides – Matt Joiner Nov 07 '09 at 11:54
  • 5
    There 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. – Patrick Schlüter May 05 '10 at 13:20
  • You 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). – Tomas Pruzina May 14 '13 at 04:11
65

fopen vs open in C

  1. fopen is a library function while open is a system call.

  2. fopen provides buffered IO which may be faster compared 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 *) while open returns an integer that identifies the file.

  5. A FILE * gives you the ability to use fscanf and other stdio.h functions.

user16217248
  • 3,119
  • 19
  • 19
  • 37
Yogeesh H T
  • 2,777
  • 21
  • 18
  • 15
    `open` is a POSIX standard, so it's quite portable – osvein Oct 05 '17 at 13:22
  • `fopen()` is not [async-signal-safe](https://man7.org/linux/man-pages/man7/signal-safety.7.html) (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. Using `open()` adds complexity and misses the buffered-io, ... – Simon Sobisch Jun 16 '21 at 18:47
  • @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. – Jiminion May 02 '22 at 14:40
  • @Jiminion *Works fine with Linuxes, but is now deprecated in Windows.* [Microsoft also quite risibly "deprecates" `fopen()`](https://stackoverflow.com/questions/14386/fopen-deprecated-warning). [And `strcpy()`](https://stackoverflow.com/questions/4012222/c-strcpy-gives-a-warning-c4996). Along with probably half the required functions in C. *You are supposed to use _open, _close now.* No, you're not "supposed to". "Microsoft wants you to because it's not portable" [is probably closer to the mark](https://en.wikipedia.org/wiki/Embrace,_extend,_and_extinguish#Examples_by_Microsoft). – Andrew Henle Mar 13 '23 at 02:08
  • 4
    *`open` is a **system call**.* Ugh. I don't know why this meaningless artificial demarcation exists. `open()` on just about every extant POSIX system is a **library function** exactly like `fopen()` is. The `open()` **library function** is usually implemented around the `openat` **system call**. And even then, before there was an `openat()` system call, `open()` was a **library function** wrapped around the `open()` system call anyway. `fopen()` is just a bigger library function wrapper around the same system call that the `open()` library function uses. – Andrew Henle Mar 13 '23 at 15:34
  • @osvein - Andrew is right. And the distinction is important to remember. The open libc function is a function that wraps a system call. On newer versions of libc it actually wraps the `openat` system call. – Omnifarious Aug 21 '23 at 06:26
20

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.

chwarr
  • 6,777
  • 1
  • 30
  • 57
user7116
  • 63,008
  • 17
  • 141
  • 172
12

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.

dreamlax
  • 93,976
  • 29
  • 161
  • 209
9

open() is a system call and specific to Unix-based systems and it returns a file descriptor. You can write to a file descriptor using write() which is another system call.
fopen() is an ANSI C function call which returns a file pointer and it is portable to other OSes. We can write to a file pointer using fprintf.

In Unix:
You can get a file pointer from the file descriptor using:

fP = fdopen(fD, "a");

You can get a file descriptor from the file pointer using:

fD = fileno (fP);
Pang
  • 9,564
  • 146
  • 81
  • 122
Arun Chettoor
  • 1,021
  • 1
  • 12
  • 17
8

Using open, read, write means you have to worry about signal interaptions.

If the call was interrupted by a signal handler the functions will return -1 and set errno to EINTR.

So the proper way to close a file would be

while (retval = close(fd), retval == -1 && ernno == EINTR) ;
digy
  • 2,663
  • 3
  • 19
  • 14
  • 5
    For `close`, this depends on the operating system. It's incorrect to do the loop on Linux, AIX and some other operating systems. – strcat Dec 30 '13 at 22:29
  • In 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. – Marcelo Jul 05 '18 at 20:55
  • I'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 return `EINTR`? –  Mar 10 '22 at 16:37
6

I changed to open() from fopen() for my application, because fopen was causing double reads every time I ran fopen fgetc . Double reads were disruptive of what I was trying to accomplish. open() just seems to do what you ask of it.

Ersatz Splatt
  • 61
  • 1
  • 1
4

open() will be called at the end of each of the fopen() family functions. open() is a system call and fopen() are provided by libraries as a wrapper functions for user easy of use

theadnangondal
  • 1,546
  • 3
  • 14
  • 28
3

Depends also on what flags are required to open. With respect to usage for writing and reading (and portability) f* should be used, as argued above.

But if basically want to specify more than standard flags (like rw and append flags), you will have to use a platform specific API (like POSIX open) or a library that abstracts these details. The C-standard does not have any such flags.

For example you might want to open a file, only if it exits. If you don't specify the create flag the file must exist. If you add exclusive to create, it will only create the file if it does not exist. There are many more.

For example on Linux systems there is a LED interface exposed through sysfs. It exposes the brightness of the led through a file. Writing or reading a number as a string ranging from 0-255. Of course you don't want to create that file and only write to it if it exists. The cool thing now: Use fdopen to read/write this file using the standard calls.

Ritualmaster
  • 206
  • 1
  • 9
-1

Opening a file using fopen

Before we can read(or write) information from (to) a file on disk, we must open the file. To open the file, we call the function fopen().

  1. fopen() searches the disk for the file to be opened.
  2. Then, it loads the file from disk into a place in memory called the buffer.
  3. Finally, it sets up a character (char) pointer that points to the first character of the buffer.

Sometimes, during the buffering process, fopen() may time out.

So, when comparing the fopen() library call (high-level i/o) to the open() (low-level i/o) system call, it is faster and more appropriate to use open() rather than fopen().

cafce25
  • 15,907
  • 4
  • 25
  • 31
prashad
  • 107
  • 2
  • 15