What is a File Descriptor
A file descriptor is a small non-negative integer that a process uses to refer to an open file, socket, pipe, or device. When you open a file, the kernel creates an entry in the process's file descriptor table and returns the integer index. All subsequent reads, writes, and closes use that integer.
How it works
Every process starts with three file descriptors already open:
- 0 (stdin) — standard input
- 1 (stdout) — standard output
- 2 (stderr) — standard error
When you call open("/etc/hosts"), the kernel finds the file's inode, creates an open file description (tracking the current read/write position), and assigns the lowest available file descriptor — usually 3. The returned integer is your handle to that file.
The file descriptor table is per-process. File descriptor 3 in one process is completely unrelated to file descriptor 3 in another. When a process forks, the child inherits copies of the parent's file descriptors — this is how shell pipelines work. The pipe's write end is stdout in one process and the read end is stdin in the next.
The Unix design principle "everything is a file" means file descriptors aren't just for files:
- Network sockets —
connect()returns a file descriptor. You read and write network data through it. - Pipes —
pipe()creates two file descriptors, one for reading and one for writing. - Devices —
/dev/null,/dev/random, terminal devices are all accessed through file descriptors. - Epoll/kqueue — event polling systems monitor multiple file descriptors for readiness.
Each process has a limit on how many file descriptors it can open (often 1024 by default, configurable to millions). Leaking file descriptors — opening without closing — is a common bug that eventually causes open calls to fail with "too many open files."
Why it matters
File descriptors are the universal I/O interface in Unix systems. Every network connection, every pipe between processes, every file read passes through a file descriptor. Understanding them explains shell redirections (2>&1), why servers monitor socket readiness, and why "too many open files" crashes services. They are the concrete mechanism behind the abstraction of I/O.
See How Processes Work for how file descriptors fit into process creation and management.