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.
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).
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.
#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
#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.
fopenreturn value — catches the file not existing or being inaccessible at allferror()— distinguishes a genuine I/O error from a clean end-of-filefeof()— confirms a stream simply ran out of dataperror()— turns the currenterrnointo a readable message for the user or a log