Skip to Content
Course content

84: File Positioning: fseek, ftell, rewind

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Up until now, we've mostly treated files like a stream—you start at the beginning and read until you hit the end. But in the real world, especially when dealing with binary files or large databases, that's incredibly inefficient. You don't want to read 10,000 records just to get to the 10,001st. That's where file positioning comes in.

How do I jump to a specific spot in a file?

This is where fseek is your best friend. Think of it like a record player needle; you're telling C exactly where to drop the needle. The function takes three arguments: the file pointer, the offset (how many bytes to move), and the "origin" (where you're counting from).

I usually recommend using fixed-size structs when you need to seek, because it makes the math trivial. If every record is 64 bytes, the 5th record is simply at 4 * 64.

typedef struct {
    int id;
    char name[20];
    int score;
} Player;

// Let's jump to the 3rd player in a binary file
FILE *fp = fopen("scores.dat", "rb");
if (fp) {
    // SEEK_SET means "start from the beginning of the file"
    fseek(fp, 2 * sizeof(Player), SEEK_SET);
    
    Player p;
    fread(&p, sizeof(Player), 1, fp);
    printf("Player 3: %s - %d\n", p.name, p.score);
    fclose(fp);
}

You have three options for the origin: SEEK_SET (the start), SEEK_CUR (where you are right now), and SEEK_END (the very end). If you use SEEK_END with a negative offset, you can actually jump backward from the end of the file.

How can I tell where I am, or find out how big a file is?

If you've been doing a lot of reading and writing and you've lost track of your position, ftell will give you the current byte offset from the start of the file. It returns a long, which represents the number of bytes from the beginning.

A common trick I use to find the total size of a file is to "teleport" to the end, ask ftell where it is, and then jump back to where I started. It's a bit of a dance, but it's the standard way to do it in C.

FILE *fp = fopen("data.bin", "rb");
fseek(fp, 0, SEEK_END);          // Jump to the end
long fileSize = ftell(fp);       // Get the current position (which is the size)
rewind(fp);                      // Go back to the start so we can actually read it

printf("The file is %ld bytes long.\n", fileSize);
fclose(fp);

Is rewind() just a shortcut for fseek()?

Essentially, yes. Calling rewind(fp) is functionally the same as calling fseek(fp, 0, SEEK_SET). However, there is one subtle difference: rewind also clears the error indicators for the stream.

If you've hit the end of the file (EOF), ftell and fseek might behave predictably, but some internal error flags remain set. rewind wipes the slate clean. I personally use rewind because it's cleaner to read and tells anyone looking at my code exactly what my intention is: "I'm starting over."




📋 Practical Task

Exercise: Binary Record Random-Access Reader

Create a program that manages a binary file of User records. Each User struct should contain an int id and a char username[32].

  1. First, write a small helper function to populate a file named users.bin with 10 dummy records.
  2. In your main function, prompt the user to enter a record index (0-9).
  3. Use fseek to jump directly to that specific record without reading the preceding ones.
  4. Read the record and print the username.
  5. Finally, use ftell to print the exact byte offset where the record was read.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.