All system calls for performing I/O refer to open files using a file descriptor, a (usually small) nonnegative integer. File descriptors are used to refer to all types of open files, including pipes, FIFOs, sockets, terminals, devices, and regular files. Each process has its own set of file descriptors.
By convention, most programs expect to be able to use the three standard file descriptors listed in Table 4-1. These three descriptors are opened on the program’s behalf by the shell, before the program is started. Or, more precisely, the program inherits copies of the shell’s file descriptors, and the shell normally operates with
these three file descriptors always open. (In an interactive shell, these three file
descriptors normally refer to the terminal under which the shell is running.) If I/O
redirections are specified on a command line, then the shell ensures that the file
descriptors are suitably modified before starting the program.
When referring to these file descriptors in a program, we can use either the numbers
(0, 1, or 2) or, preferably, the POSIX standard names defined in <unistd.h>.
Although the variables stdin, stdout, and stderr initially refer to the process’s
standard input, output, and error, they can be changed to refer to any file by
using the freopen() library function. As part of its operation, freopen() may
change the file descriptor underlying the reopened stream. In other words,
after an freopen() on stdout, for example, it is no longer safe to assume that the
underlying file descriptor is still 1.
The following are the four key system calls for performing file I/O (programming languages and software packages typically employ these calls only indirectly, via I/O libraries):
- fd = open(pathname, flags, mode) opens the file identified by pathname, returning a file descriptor used to refer to the open file in subsequent calls. If the file doesn’t exist, open() may create it, depending on the settings of the flags bitmask argument. The flags argument also specifies whether the file is to be opened for reading, writing, or both. The mode argument specifies the permissions to be placed on the file if it is created by this call. If the open() call is not being used to create a file, this argument is ignored and can be omitted.
- numread = read(fd, buffer, count) reads at most count bytes from the open file
referred to by fd and stores them in buffer. The read() call returns the number of
bytes actually read. If no further bytes could be read (i.e., end-of-file was
encountered), read() returns 0.