I learned that by default I/O in programs is buffered, i.e they are served from a temporary storage to the requesting program.
I understand that buffering improves IO performance (maybe by reducing system calls). I have seen examples of disabling buffering, like setvbuf
in C. What is the difference between the two modes and when should one be used over the other?
2 Answers
You want unbuffered output whenever you want to ensure that the output has been written before continuing. One example is standard error under a C runtime library - this is usually unbuffered by default. Since errors are (hopefully) infrequent, you want to know about them immediately. On the other hand, standard output is buffered simply because it's assumed there will be far more data going through it.
Another example is a logging library. If your log messages are held within buffers in your process, and your process dumps core, there a very good chance that output will never be written.
In addition, it's not just system calls that are minimized but disk I/O as well. Let's say a program reads a file one byte at a time. With unbuffered input, you will go out to the (relatively very slow) disk for every byte even though it probably has to read in a whole block anyway (the disk hardware itself may have buffers but you're still going out to the disk controller which is going to be slower than in-memory access).
By buffering, the whole block is read in to the buffer at once then the individual bytes are delivered to you from the (in-memory, incredibly fast) buffer area.
Keep in mind that buffering can take many forms, such as in the following example:
+-------------------+-------------------+
| Process A | Process B |
+-------------------+-------------------+
| C runtime library | C runtime library | C RTL buffers
+-------------------+-------------------+
| OS caches | Operating system buffers
+---------------------------------------+
| Disk controller hardware cache | Disk hardware buffers
+---------------------------------------+
| Disk |
+---------------------------------------+

- 854,327
- 234
- 1,573
- 1,953
-
The graph is wonderful. One thing worth mentioning is that a `FILE` object (a stream)'s internally buffer is completely different from a `fgets` required buffer parameter. This just confused me for hours before I wrote some code to figure it out. QAQ – Rick Mar 07 '19 at 09:02
-
No one reads files one byte at a time anyway do they? – user16217248 Feb 27 '22 at 04:08
-
@user16217248: Sure they do. A standard I/O filter program often uses `getchar/putchar` and relies on the buffering to provide efficiencies, at least in terms of trips to the I/O devices. – paxdiablo Feb 27 '22 at 04:29
-
@paxdiablo But if I `open` a file, perform a single large `read`/`write` then `close` will it be any slower unbuffered? – user16217248 Feb 27 '22 at 04:42
-
@user16217248: possibly, but you don't often *know* the properties of the underlying source (or destination) of data. Is it from standard input from a file, is it a local file, a network-mounted file, a terminal device running at 300 bits per second, a pipe connected to another process that may deliver data sporadically? The power of the UNIX file model ("everything is a file") also makes it hard to definitively tailor I/O strategies. – paxdiablo Feb 27 '22 at 04:50
-
@paxdiablo A file on the disk, such as a configuration file for an application – user16217248 Feb 27 '22 at 04:51
-
@user16217248: a config file is likely to be small enough to be read into memory in its entirety and used from there (and also likely to be on a local disk, though not guaranteed). For something like that, I'd probably try to read 10K chunks since it will most likely only take one read operation and 10K is not *too* much wastage if your config file is only twenty bytes long :-) – paxdiablo Feb 27 '22 at 04:52
-
@paxdiablo Thanks for this answer. when you mention "OS caches" do you actually mean those hardware CPU caches such as L1, L2, L3 etc or the "OS caches" is some kind of buffer in the kernel space memory? – torez233 Sep 14 '22 at 23:59
-
@torez233: I meant caches at the OS level. CPU caches are much lower-level, more to do with memory accesses than file I/O. – paxdiablo Sep 15 '22 at 09:43
You want unbuffered output when you already have large sequence of bytes ready to write to disk, and want to avoid an extra copy into a second buffer in the middle.
Buffered output streams will accumulate write results into an intermediate buffer, sending it to the OS file system only when enough data has accumulated (or flush()
is requested). This reduces the number of file system calls. Since file system calls can be expensive on most platforms (compared to short memcpy
), buffered output is a net win when performing a large number of small writes. Unbuffered output is generally better when you already have large buffers to send -- copying to an intermediate buffer will not reduce the number of OS calls further, and introduces additional work.
Unbuffered output has nothing to do with ensuring your data reaches the disk; that functionality is provided by flush()
, and works on both buffered and unbuffered streams. Unbuffered IO writes don't guarantee the data has reached the physical disk -- the OS file system is free to hold on to a copy of your data indefinitely, never writing it to disk, if it wants. It is only required to commit it to disk when you invoke flush()
. (Note that close()
will call flush()
on your behalf).

- 8,465
- 6
- 41
- 47

- 3,454
- 23
- 26
-
Will calling `flush()` guarantee it's written to disk? I thought that only passed it along to the disk's buffer. – jrdioko Jul 14 '11 at 23:24
-
2
-
Unbuffered IO ks about being written to disk. Hence the term unbuffered (no intermediate buffer but directly written to disk) for winapi you call CreateFile with FILE_FLAG_NO_BUFFERING and FILE_FLAG_WRITE_THROUGH to ensure data goes directly do persistence after each write. For some other os idont know. – Martin Kosicky Aug 29 '20 at 18:14