fseek() / ftell() / rewind() / feof()
| Since: | C89(1989) |
|---|
Functions for moving and retrieving the current file position (file position indicator), and for checking whether the end of a file has been reached. Use these for file processing that requires random access.
Syntax
// Returns: 0 on success, nonzero on failure. int fseek(FILE *stream, long offset, int whence); // Returns: current position, or -1L on error. long ftell(FILE *stream); // Rewinds the file position to the beginning (also clears the error flag). void rewind(FILE *stream); // Returns: nonzero if EOF has been reached, 0 otherwise. int feof(FILE *stream);
whence (reference point) values
| Constant | Reference point | Description |
|---|---|---|
| SEEK_SET | Beginning of file | Moves to offset bytes from the beginning. offset must be 0 or greater. |
| SEEK_CUR | Current position | Moves offset bytes forward or backward from the current position. A negative value moves backward. |
| SEEK_END | End of file | Moves offset bytes from the end of the file. To get the file size, pass 0 as offset. |
Sample code
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *fp = fopen("lines.txt", "rb");
if (fp == NULL) { perror("fopen"); return EXIT_FAILURE; }
fseek(fp, 0, SEEK_END); // Move to the end of the file.
long file_size = ftell(fp); // Current position equals the file size in bytes.
printf("File size: %ld bytes\n", file_size);
rewind(fp); // Return to the beginning.
printf("Position after rewind: %ld\n", ftell(fp)); // Prints "0".
// Move to byte 7 from the beginning with SEEK_SET and read from there.
fseek(fp, 7, SEEK_SET);
char buf[64];
if (fgets(buf, sizeof(buf), fp) != NULL) {
printf("From byte 7: %s", buf); // Prints the content of the second line.
}
// Use feof to confirm the loop ended at EOF (checking the return value avoids double-processing the last line).
rewind(fp);
int ch;
int count = 0;
while ((ch = fgetc(fp)) != EOF) {
count++;
}
if (feof(fp)) {
printf("Reached end of file normally. Character count: %d\n", count);
}
fclose(fp);
return 0;
}
Common Mistakes
Common Mistake: The while (!feof(fp)) Pattern
feof() only checks whether the end-of-file flag is set. Using while (!feof(fp)) as a loop condition causes the last piece of data to be processed twice.
#include <stdio.h>
int main(void) {
FILE *fp = fopen("test.txt", "w");
if (fp == NULL) return 1;
fputs("hello\n", fp);
fclose(fp);
fp = fopen("test.txt", "r");
if (fp == NULL) return 1;
char buf[32];
/* NG: the last line may be output twice */
while (!feof(fp)) {
if (fgets(buf, sizeof(buf), fp) != NULL) {
printf("NG: %s", buf);
}
}
fclose(fp);
return 0;
}
Use the correct pattern of checking the return value of fgets() for NULL.
feof_ok.c
#include <stdio.h>
int main(void) {
FILE *fp = fopen("test.txt", "r");
if (fp == NULL) return 1;
char buf[32];
/* OK: check for EOF using the return value of fgets */
while (fgets(buf, sizeof(buf), fp) != NULL) {
printf("OK: %s", buf);
}
fclose(fp);
return 0;
}
Run the following command:
gcc feof_ok.c -o feof_ok ./feof_ok OK: hello
Notes
Calling fseek() on a file opened in text mode with any combination other than SEEK_SET and a value returned by ftell() produces implementation-defined behavior. Always open the file in binary mode ("rb") when random access is needed.
feof() only checks whether the end-of-file flag has been set. Using while (!feof(fp)) as a loop condition can cause the last piece of data to be processed twice. Checking for EOF using the return value of fgets() or fgetc() avoids this issue.
For general file read/write functions, see also 'fread() / fwrite()' and 'fgets() / fputs()'.
If you find any errors or copyright issues, please contact us.