Files & I/O

everything is a file

Imagine a workshop where every tool - the drill, the hose, the radio, the mailbox - had the same kind of handle. You would only need to learn one grip and you could operate them all. Unix made that design choice for the computer: a huge variety of very different things are made to look like a file, so the same handful of operations works on all of them.

Concretely, 'everything is a file' means that disk files, directories, terminals, keyboards, network connections, pipes between programs, and even some kernel internals are all reached through file descriptors and the same calls - open(), read(), write(), close(), lseek(). A program reading from the keyboard and a program reading from a file both just call read() on a descriptor; they often do not need to know or care which kind of thing is on the other end. Special device files under /dev expose hardware this way: writing bytes to /dev/null discards them, reading from /dev/urandom gives you random bytes, all through ordinary read and write. This is why redirection and pipes are so powerful - a program that reads fd 0 and writes fd 1 can be wired to a file, a terminal, or another program without changing a line.

Why it matters: this uniform interface is one of the deepest ideas in Unix, and it is why Unix-like systems compose so well from small tools. The slogan is a simplification, though - not literally everything is a file (network sockets, for instance, need extra calls like connect() and accept() that plain files do not), and the things you read from a pipe or a socket behave differently than a seekable disk file. But the core insight holds: by funnelling wildly different resources through one small interface, the system stays simple and tools become endlessly combinable.

$ echo hello > /dev/null # write to the bit bucket, bytes vanish $ cat file.txt | wc -l # cat's stdout is a pipe, read like any file $ wc -l < file.txt # wc's stdin is a file instead

The same wc program reads from a pipe or a file with no change - both are just descriptors.

It is a slogan, not a law: sockets need their own calls, and reads on pipes, terminals, and sockets are not seekable like a disk file. Treat 'everything is a file' as a powerful default, not a guarantee that every fd behaves identically.

Also called
the file abstractionuniform I/O interface統一 I/O 介面