CFile Error Handling

File Error Handling

Every operation covered on the previous file-handling pages — opening, reading, writing, seeking — can fail. This page pulls together the tools C provides for detecting exactly what went wrong and reacting to it gracefully instead of crashing or silently producing bad data.

Recap: Always Check fopen()

The very first line of defense is checking whether fopen actually succeeded, since every later operation is meaningless if it did not.

C
FILE *fp = fopen("data.txt", "r");
if (fp == NULL) {
    /* handle the failure here, do not proceed to use fp */
}
ferror() — Did a Stream Error Occur?

Once a file is open, ferror(fp) returns nonzero if an error indicator has been set on that stream by some previous operation (for example, a fread that failed due to a disk read error).

C
int ferror(FILE *fp);
feof() — End-of-File vs a Real Error

When a read function like fread or fgetc returns a value that looks like failure, that could mean two very different things: the file simply ran out of data (end-of-file, not really an error), or something actually went wrong while reading. feof(fp) tells them apart — it returns nonzero only once end-of-file has genuinely been reached, leaving ferror to report true failures.

Situation

feof(fp)

ferror(fp)

Read stopped because there was no more data

Nonzero

Zero

Read stopped because of an actual I/O error

Zero

Nonzero

Read succeeded normally

Zero

Zero

perror() — Human-Readable Error Messages

Many library functions, including fopen, set the global errno variable to a code describing what went wrong when they fail. perror(prefix) prints that prefix followed by a colon and a human-readable description of the current errno value — a fast way to report a clear error message without manually translating error codes. See the errno page for more on how errno works in general.

C
#include <stdio.h>

int main(void)
{
    FILE *fp = fopen("missing.txt", "r");
    if (fp == NULL) {
        perror("fopen failed");
        return 1;
    }
    fclose(fp);
    return 0;
}
fopen failed: No such file or directory
Worked Example: Handling a Missing File Gracefully

C
#include <stdio.h>

int main(void)
{
    FILE *fp = fopen("scores.txt", "r");

    if (fp == NULL) {
        perror("Could not open scores.txt");
        printf("Falling back to default settings.\n");
        return 0;   /* recover instead of crashing */
    }

    char line[100];
    while (fgets(line, sizeof(line), fp) != NULL) {
        printf("%s", line);
    }

    if (ferror(fp)) {
        printf("A read error occurred while processing the file.\n");
    } else if (feof(fp)) {
        printf("Reached the end of the file normally.\n");
    }

    fclose(fp);
    return 0;
}
Could not open scores.txt: No such file or directory
Falling back to default settings.
The recurring theme
File I/O touches the outside world — disks, permissions, other processes — none of which your program controls. Treat `NULL` returns from `fopen`, short reads/writes, and nonzero `ferror` results as expected, routine conditions to check for, not as rare edge cases to ignore.
  • fopen return value — catches the file not existing or being inaccessible at all

  • ferror() — distinguishes a genuine I/O error from a clean end-of-file

  • feof() — confirms a stream simply ran out of data

  • perror() — turns the current errno into a readable message for the user or a log