Files & I/O

unbuffered versus buffered I/O

Imagine carrying water from a well to your house. You could run back and forth with a cup each time you need a sip - many trips, a lot of effort per sip. Or you could fill a bucket once and pour cups from it at home - fewer trips, the bucket doing the saving. Unbuffered I/O is the cup; buffered I/O is the bucket.

Unbuffered (raw) I/O means calling the system calls read() and write() directly on a file descriptor. Each call crosses from your program into the kernel - a context switch with real cost - and moves exactly the bytes you asked for. Writing a file one byte at a time this way means one system call per byte, which is brutally slow. Buffered I/O, provided by the C standard library's stdio, wraps a descriptor in a FILE object (a FILE pointer, FILE *) and keeps an in-memory buffer. You use fopen(), fread(), fwrite(), fgetc(), fputc(), fprintf(), fclose(). When you write, bytes pile up in the buffer; only when it fills (or you flush or close) does the library make one big write() to the kernel. When you read, the library grabs a big chunk with one read() and hands you small pieces from the buffer. Many of your operations become zero system calls.

Why it matters: this is the most important performance distinction in everyday file handling. Buffered stdio is usually what you want for ordinary file work because it turns thousands of tiny syscalls into a few large ones. But buffering adds a layer between you and the kernel: data you 'wrote' may still be sitting in the user-space buffer, not on disk, until a flush - which surprises people debugging with print statements, and matters for durability. When you need exact control, precise timing, or you are talking to a device, drop to raw read()/write() instead.

/* unbuffered: one syscall per call */ write(1, "a", 1); write(1, "b", 1); /* buffered: nothing reaches the kernel until the buffer fills or you flush */ FILE *f = fopen("out", "w"); fputc('a', f); fputc('b', f); fclose(f);

Two write() calls = two trips to the kernel; two fputc() calls = zero trips until fclose flushes.

Do not mix raw read()/write() and buffered stdio on the same open file without care - the stdio buffer and the kernel offset can drift out of sync, giving baffling results. Pick one layer per file.

Also called
raw I/O vs stdiosystem calls vs FILE*原始 I/O 對比標準 I/O