Introduction
A file descriptor is a handle that a process uses to work with an already opened file or I/O resource. It is usually a small integer, such as 0, 1, 2, or 3.
The file descriptor is not the file itself. It acts as an index in the process's file descriptor table, which the kernel uses to find the corresponding open-file information. This allows the process to perform operations such as reading from or writing to the file.
Why File Descriptors Exist
User programs should not directly access kernel file objects or disk structures. That would make the system unsafe because a program could corrupt file-system state or interfere with another process.
Instead, applications use system calls. When a program opens a file, the operating system checks permissions, creates kernel-side open-file state, and returns a file descriptor as a safe handle.
File Descriptor Meaning
A file descriptor is a small non-negative integer used by a process to refer to an open file or I/O resource. Common system calls use this descriptor:
read: Reads bytes from the opened resource.
write: Writes bytes to the opened resource.
lseek: Changes the current file offset.
close: Removes the process’s reference to the opened resource.
The descriptor number has meaning only through the process that owns it.
File Descriptors and its Need
Common File Descriptors
When a process starts, some descriptors are usually already set up by convention.
Descriptor | Common Meaning |
|---|---|
| Standard input |
| Standard output |
| Standard error |
| Often the first extra descriptor returned by |
If descriptors 0, 1, and 2 are already used, opening a new file often returns 3. If descriptor 3 is later closed, a future open() may reuse 3.
Process-Local Meaning
File descriptor numbers are process-local. This means descriptor 3 in one process does not automatically refer to the same file as descriptor 3 in another process. Each process has its own file descriptor table. The kernel interprets the descriptor number using that process’s table, not a single global descriptor numbering system.
So the same number can exist in many processes, but each process decides what that number points to through its own descriptor table.
Internal Three-Layer Model
A file descriptor usually leads through three conceptual layers.
File Descriptor Table: A per-process table indexed by file descriptor numbers.
Open File Description: Stores kernel state for the opened file, such as the current offset and access flags.
Inode / File Object: Stores metadata about the actual file and information needed to locate its data blocks.
The descriptor table entry does not contain the whole file. It points to an open file description, and that open file description points to the underlying file object.
Open, Read, Lseek, Write, Close
Consider this sequence:
fd = open("a.txt")read(fd, buffer, 100)lseek(fd, 0, SEEK_SET)write(fd, data, 20)close(fd)Here is the compact flow:
open: Resolves the path, checks permissions, creates open-file state, and returns a descriptor.
read: Uses the descriptor to find the open file description and reads from the current offset.
lseek: Changes the current offset stored in the open file description.
write: Writes from the current offset and usually advances it.
close: Removes the process’s reference to that opened resource.
The important point is that read, write, and lseek operate through the descriptor, but the actual state is kept inside the kernel.
Open, Read, Lseek, Write, Close
Current Offset
The current offset tells where the next read or write should start. It is stored in the open file description, not as ordinary file contents on disk. Reads and writes usually advance the offset by the number of bytes processed. lseek() changes the offset value, but it does not immediately move a physical disk head; it changes kernel open-file state.
This is why two descriptors can behave differently or similarly depending on whether they point to separate or shared open file descriptions.
Fork, Dup, and Shared Offset
After fork(), the child process inherits the parent’s file descriptors. The parent and child have separate descriptor tables, but inherited entries may point to the same open file description.
Similarly, dup(fd) creates another descriptor that points to the same open file description. If descriptor 3 is duplicated into descriptor 4, both descriptors can share the same current offset.
Case | Offset Behavior |
|---|---|
Same file opened twice independently | Usually separate offsets |
Descriptor duplicated with | Shared offset |
Descriptor inherited through | Shared offset |
This distinction is important because the descriptor number is only the process-side handle. The open file description is where the shared open-file state lives.
Summary
A file descriptor is a small integer handle that a process uses to access an open file or I/O resource through system calls. It keeps user programs away from direct kernel file objects while still giving them controlled access.
The clean model is: descriptor table belongs to the process, open file description stores open-file state, and inode or file object stores file metadata and block mapping. open, read, write, lseek, close, fork, and dup all make more sense with this separation.
Be the first to add a comment.