C Programming - Beginner to Brilliance / File Handling in C

Error Handling in Files

When working with files, errors can and will happen—files may be missing, corrupted, opened in the wrong mode, or disk issues may occur. Therefore, it’s crucial to implement error handling to avoid unexpected crashes or data loss.


📌 Why Error Handling in File I/O is Important

Think about these scenarios:

  • Trying to read a file that doesn’t exist ❌

  • No permission to write to a file 🔒

  • Disk is full while writing 🧯

  • File pointer is accidentally NULL 💀

Without proper error checks, your program might:

  • Crash

  • Produce incorrect output

  • Corrupt files or lose data


🔍 Common File Operation Errors

❌ Error Situation

😱 Consequence

File doesn't exist (fopen)

fp becomes NULL

Reading from a write-only file

Undefined behavior

Writing to a read-only file

Nothing happens / segmentation fault

Forgetting to close a file

Memory/resource leaks

Reaching end-of-file unexpectedly

Infinite loops or garbage values


🧪 How to Check for Errors

✅ Check if the File Opened Successfully

FILE *fp = fopen("data.txt", "r");
if (fp == NULL) {
    printf("❌ Error: Could not open file!\\n");
    return 1;
}

✅ Use feof() to Check for End of File

feof() is used to determine whether the end of a file has been reached during input operations. It helps avoid reading past the end of a file.

while (!feof(fp)) {
    // Read or process file here
}

⚠️ Note: feof() returns true after an attempt to read past the end. So it’s often better to check the return value of fscanf, fgets, etc.


✅ Use ferror() to Check for Errors During File I/O

ferror() checks whether an error has occurred during a previous file operation (like reading or writing). It helps identify unexpected file access problems.

if (ferror(fp)) {
    printf("⚠️ Error occurred while reading/writing the file.\\n");
}
  • ferror(FILE *stream) returns a non-zero value if an error occurred.


🔄 Resetting File Errors

Use clearerr() to reset error and EOF flags on a file stream.

clearerr(fp);

This is useful if you're retrying operations on a file.


💡 Common File Error Handling Pattern

FILE *fp = fopen("data.txt", "r");

if (fp == NULL) {
    perror("Error opening file"); // Built-in descriptive error
    return 1;
}

// Read something
char ch = fgetc(fp);
if (ferror(fp)) {
    printf("⚠️ Error reading from file\\n");
    clearerr(fp);
}

fclose(fp);

🔧 perror() and strerror()

C gives you ways to print descriptive error messages using the global errno variable.

✅ Using perror()

perror() prints a human-readable error message to stderr based on the last error that occurred. It uses the global errno value and provides quick diagnostics.

perror("File error");  // Automatically prints a descriptive message

✅ Using strerror() and errno

strerror() converts the numeric error code in errno to a readable string message, explaining the cause of the error in detail.

errno is a global variable set by system/library calls when an error occurs.

#include <errno.h>
#include <string.h>

printf("Error: %s\\n", strerror(errno));

These help you know why the operation failed (like “Permission denied”, “No such file or directory”, etc.)


🧠 Example: Full Error-Handled File Read

#include <stdio.h>
#include <errno.h>
#include <string.h>

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

    if (fp == NULL) {
        printf("❌ File open failed: %s\\n", strerror(errno));
        return 1;
    }

    char ch;
    while ((ch = fgetc(fp)) != EOF) {
        putchar(ch);
    }

    if (ferror(fp)) {
        printf("⚠️ Error occurred during file read!\\n");
    }

    fclose(fp);
    return 0;
}

Output:

🔸 Case 1: File Does Not Exist

❌ File open failed: No such file or directory

🔸 Case 2: File Exists and Contains Text

example.txt contains the following data:

Hello World!
This is a test.

The output will be:

Hello World!
This is a test.

If any read error occurs during file reading, this message will also appear:

⚠️ Error occurred during file read!

(but only if something goes wrong while reading, like a hardware issue or corrupted file stream).


🎯 Best Practices for File Error Handling

✅ Always check if fopen() succeeded

✅ Check I/O results (fgets(), fscanf() return values)

✅ Use ferror() or feof() to catch problems

✅ Use fclose() in all cases, even if an error occurs

✅ Use perror() or strerror() to inform the user