the file offset and lseek
/ lseek -> EL-seek /
Think of reading a long book with a single bookmark. Each time you read a page, the bookmark advances; you do not start from page one every time. A file has exactly one such bookmark per open: the file offset, a number saying how many bytes from the start the next read or write will happen.
Concretely, the file offset is a count of bytes from the beginning of the file, stored in the open-file structure your descriptor points at. It starts at 0 when you open (unless you used O_APPEND). Every read(fd, buf, n) that moves k bytes advances the offset by k; every write does the same. So calling read three times in a row naturally walks forward through the file - no extra effort needed. When you want to jump instead of crawl, lseek(fd, offset, whence) moves the bookmark explicitly: whence is SEEK_SET (offset is measured from the start), SEEK_CUR (relative to the current position, can be negative), or SEEK_END (relative to the end). lseek(fd, 0, SEEK_CUR) is a handy trick to ask 'where am I now?' without moving. Seeking past the end of a file and writing creates a hole (a sparse file) where the gap reads back as zero bytes.
Why it matters: the offset is why sequential reading 'just works' and why random access is possible at all. It also explains a subtlety: because the offset lives in the shared open-file structure, two descriptors made by dup() share one offset (reading through one moves it for both), while two independent open() calls on the same file get separate offsets. Pipes, terminals, and sockets are not seekable - lseek() on them fails with ESPIPE, because there is no fixed position to seek to.
off_t pos = lseek(fd, 0, SEEK_CUR); /* where am I now? */ lseek(fd, 0, SEEK_SET); /* rewind to the start */ lseek(fd, -4, SEEK_END); /* 4 bytes before the end */
lseek moves the bookmark explicitly; reading and writing move it implicitly.
The offset belongs to the open-file description, not the descriptor itself, so dup'd descriptors share it but separate open() calls do not. lseek does not read or write any data - it only repositions the bookmark.