File Positioning (fseek/ftell)
Every open file has a current position — the offset, in bytes, where the next read or write will happen. Sequential I/O functions like fgets and fread automatically advance this position as they consume data; fseek, ftell, and rewind let you inspect and control it directly, enabling random access instead of a strictly front-to-back read.
ftell() — Where Am I?
long ftell(FILE *fp);
ftell returns the current byte offset within the file, or -1L on failure. It is the read-only counterpart to fseek.
fseek() — Jump to a Position
int fseek(FILE *fp, long offset, int whence);
whence value | Meaning of offset |
|---|---|
| Absolute position, measured from the start of the file |
| Relative position, measured from the current position |
| Relative position, measured from the end of the file (often used with a negative offset) |
fseek returns 0 on success and nonzero on failure. Combined with the three whence constants, it can move forward, backward, or jump straight to an absolute byte offset.
rewind() — Back to the Start
rewind(fp) is a convenience shortcut, equivalent to fseek(fp, 0L, SEEK_SET) — but it also clears the file's error and end-of-file indicators, which plain fseek does not do.
Worked Example: Finding a File's Size
A common trick for finding how big a file is (in bytes) is to seek all the way to the end, ask ftell for the current position (which is now the total size), then seek back to the beginning before doing any real reading.
#include <stdio.h>
int main(void)
{
FILE *fp = fopen("data.bin", "rb");
if (fp == NULL) {
printf("Could not open file.\n");
return 1;
}
fseek(fp, 0L, SEEK_END); /* jump to the very end */
long size = ftell(fp); /* current position == total byte size */
rewind(fp); /* jump back to the start for real reading */
printf("File size: %ld bytes\n", size);
fclose(fp);
return 0;
}File size: 4096 bytes
Random Access to Binary Records
Because fseek can jump to any absolute offset, it makes it possible to treat a binary file as an array of fixed-size records on disk — jump directly to record number N by seeking to N * sizeof(Record), without reading through every record before it.
typedef struct {
char name[20];
int score;
} Player;
Player readPlayerAt(FILE *fp, int index)
{
Player p;
fseek(fp, (long) index * sizeof(Player), SEEK_SET);
fread(&p, sizeof(Player), 1, fp);
return p;
}
/* readPlayerAt(fp, 2) jumps straight to the third Player record
without reading records 0 and 1 first. */ftell— read the current positionfseek— jump to an absolute or relative positionrewind— shortcut back to byte 0, also clears error/EOF flags