16.9: Random Access (fseek, ftell, etc.)

Normally, files and streams (that is, anything accessed via a FILE *) are read and written sequentially. However, it's also possible to jump to a certain position in a file.

To jump to a position, it's generally necessary to have ``been there'' once already. First, you use the function ftell to find out what your position in the file is; then, later, you can use the function fseek to get back to a saved position.

File positions are stored as long ints. To record a position, you would use code like

	long int pos;
	pos = ftell(fp);
Later, you could ``seek'' back to that position with
	fseek(fp, pos, SEEK_SET);
The third argument to fseek is a code telling it (in this case) to set the position with respect to the beginning of the file; this is the mode of operation you need when you're seeking to a position returned by ftell.

As an example, suppose we were writing a file, and one of the lines in it contained the words ``This file is n lines long'', where n was supposed to be replaced by the actual number of lines in the file. At the time when we wrote that line, we might not know how many lines we'd eventually write. We could resolve the difficulty by writing a placeholder line, remembering where it was, and then going back and filling in the right number later. The first part of the code might look like this:

	long int nlinespos = ftell(fp);
	fprintf(fp, "This file is %4d lines long\n", 0);
Later, when we'd written the last line to the file, we could seek back and rewrite the ``number-of-lines'' line like this:
	fseek(fp, nlinespos, SEEK_SET);
	fprintf(fp, "This file is %4d lines long\n", nlines);
There's no way to insert or delete characters in a file after the fact, so we have to make sure that if we overwrite part of a file in this way, the overwritten text is exactly the same length as the previous text. That's why we used %4d, so that the number would always be printed in a field 4 characters wide. (However, since the field width in a printf format specifier is a minimum width, with this choice of width, the code would fail if a file ever had more than 9999 lines in it.)

Three other file-positioning functions are rewind, which rewinds a file to its beginning, and fgetpos and fsetpos, which are like ftell and fseek except that they record positions in a special type, fpos_t, which may be able to record positions in huge files for which even a long int might not be sufficient.

If you're ever using one of the ``read/write'' modes ("r+" or "w+"), you must use a call to a file-positioning function (fseek, rewind, or fsetpos) before switching from reading to writing or vice versa. (You can also call fflush while writing and then switch to reading, or reach end-of-file while reading and then switch back to writing.)

In binary ("b") mode, the file positions returned by ftell and used by fseek are byte offsets, such that it's possible to compute an fseek target without having to have it returned by an earlier call to ftell. On many systems (including Unix, the Macintosh, and to some extent MS-DOS), file positioning works this way in text mode as well. Code that relies on this isn't as portable, though, so it's not a good idea to treat ftell/fseek positions in text files as byte offsets unless you really have to.

Read sequentially: prev next up top

This page by Steve Summit // Copyright 1996-1999 // mail feedback