C Programming File Handling
Advanced Concepts

C File Handling - Complete Guide

Master C file handling including file operations, file modes, file functions with detailed syntax, practical examples, and programming best practices.

File Operations

Create, Read, Write, Update

File Modes

Text & Binary Modes

File Functions

Complete Reference

Introduction to File Handling in C

File handling in C enables programs to store data permanently on disk and retrieve it when needed. It's essential for creating applications that need to persist data between program executions, such as databases, configuration files, and data logs.

Why File Handling?
  • Data Persistence: Store data permanently on disk
  • Large Data Handling: Process data larger than available memory
  • Data Sharing: Share data between different programs
  • Configuration Storage: Store program settings and preferences
  • Backup & Recovery: Create backups and restore data
File Types in C
  • Text Files: Human-readable, store characters
  • Binary Files: Machine-readable, store raw bytes
  • Sequential Files: Processed in sequence
  • Random Access Files: Access any position directly

Important File Concepts

File handling involves: FILE pointer (stream pointer), Opening mode (read/write/append), File position indicator (current read/write position), and Buffer (temporary storage). Always close files after operations to prevent data loss.

File Opening Modes

File opening modes determine how a file will be accessed. Each mode has specific characteristics for text and binary files.

Mode Description File Exists File Doesn't Exist
Text File Modes
"r"
Read mode. Opens file for reading. Opens successfully Returns NULL
"w"
Write mode. Creates new file or truncates existing. Truncates to zero length Creates new file
"a"
Append mode. Opens file for writing at end. Opens, writes at end Creates new file
"r+"
Read/Write mode. Opens file for both. Opens successfully Returns NULL
"w+"
Write/Read mode. Creates/truncates file. Truncates to zero length Creates new file
"a+"
Append/Read mode. Opens for reading and appending. Opens, writes at end Creates new file
Binary File Modes
"rb"
Binary read mode. Opens successfully Returns NULL
"wb"
Binary write mode. Truncates to zero length Creates new file
"ab"
Binary append mode. Opens, writes at end Creates new file
"rb+"
Binary read/write mode. Opens successfully Returns NULL
"wb+"
Binary write/read mode. Truncates to zero length Creates new file
"ab+"
Binary append/read mode. Opens, writes at end Creates new file

C File Functions Reference Table

Complete reference of all file handling functions in C with their syntax, purpose, and return values.

Function Syntax Purpose Return Value
fopen()
FILE *fopen(const char *filename, const char *mode);
Opens a file and returns a FILE pointer FILE* on success, NULL on failure
fclose()
int fclose(FILE *stream);
Closes an opened file 0 on success, EOF on error
fgetc()
int fgetc(FILE *stream);
Reads a character from file Character read or EOF
fputc()
int fputc(int char, FILE *stream);
Writes a character to file Character written or EOF
fgets()
char *fgets(char *str, int n, FILE *stream);
Reads a string from file str on success, NULL on failure
fputs()
int fputs(const char *str, FILE *stream);
Writes a string to file Non-negative on success, EOF on error
fscanf()
int fscanf(FILE *stream, const char *format, ...);
Reads formatted input from file Number of items read
fprintf()
int fprintf(FILE *stream, const char *format, ...);
Writes formatted output to file Number of characters written
fread()
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
Reads binary data from file Number of items read
fwrite()
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
Writes binary data to file Number of items written
fseek()
int fseek(FILE *stream, long offset, int whence);
Moves file position indicator 0 on success, non-zero on error
ftell()
long ftell(FILE *stream);
Returns current file position Current position or -1L on error
rewind()
void rewind(FILE *stream);
Sets file position to beginning None (void)
feof()
int feof(FILE *stream);
Checks end-of-file indicator Non-zero if EOF, 0 otherwise
ferror()
int ferror(FILE *stream);
Checks error indicator Non-zero if error, 0 otherwise
clearerr()
void clearerr(FILE *stream);
Clears error and EOF indicators None (void)
remove()
int remove(const char *filename);
Deletes a file 0 on success, non-zero on error
rename()
int rename(const char *oldname, const char *newname);
Renames a file 0 on success, non-zero on error
Remember: Always check the return value of fopen() for NULL before proceeding. Always close files with fclose() after operations to free resources and ensure data is written to disk.

Text File Operations

Text files store data in human-readable format. Each line ends with a newline character ('\n').

Example: Basic Text File Operations
#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE *file;
    char ch;
    char text[100];
    
    // Writing to a text file
    file = fopen("example.txt", "w");
    if(file == NULL) {
        printf("Error opening file for writing!\n");
        return 1;
    }
    
    fprintf(file, "Hello, World!\n");
    fprintf(file, "This is a text file.\n");
    fprintf(file, "Line 3: %d + %d = %d\n", 5, 3, 5+3);
    fclose(file);
    printf("Data written to file successfully.\n\n");
    
    // Reading from a text file - character by character
    file = fopen("example.txt", "r");
    if(file == NULL) {
        printf("Error opening file for reading!\n");
        return 1;
    }
    
    printf("Reading file character by character:\n");
    while((ch = fgetc(file)) != EOF) {
        printf("%c", ch);
    }
    fclose(file);
    
    // Reading from a text file - line by line
    file = fopen("example.txt", "r");
    printf("\n\nReading file line by line:\n");
    
    while(fgets(text, sizeof(text), file) != NULL) {
        printf("Line: %s", text);
    }
    fclose(file);
    
    // Appending to a text file
    file = fopen("example.txt", "a");
    fprintf(file, "This line was appended.\n");
    fprintf(file, "Appended line 2.\n");
    fclose(file);
    
    printf("\nData appended successfully.\n");
    
    return 0;
}
Output:
Data written to file successfully.

Reading file character by character:
Hello, World!
This is a text file.
Line 3: 5 + 3 = 8

Reading file line by line:
Line: Hello, World!
Line: This is a text file.
Line: Line 3: 5 + 3 = 8

Data appended successfully.

Binary File Operations

Binary files store data in machine-readable format (raw bytes). They're more efficient for storing structured data like arrays and structures.

Example: Binary File Operations with Structures
#include <stdio.h>
#include <stdlib.h>

// Structure definition
typedef struct {
    int id;
    char name[50];
    float salary;
    int age;
} Employee;

int main() {
    FILE *file;
    Employee emp, empRead;
    
    // Create employee data
    Employee employees[] = {
        {101, "John Doe", 45000.50, 30},
        {102, "Jane Smith", 52000.75, 28},
        {103, "Bob Johnson", 38000.25, 35},
        {104, "Alice Brown", 61000.00, 32},
        {105, "Charlie Wilson", 48000.50, 29}
    };
    int numEmployees = 5;
    
    // Write employees to binary file
    file = fopen("employees.dat", "wb");
    if(file == NULL) {
        printf("Error opening file for writing!\n");
        return 1;
    }
    
    fwrite(employees, sizeof(Employee), numEmployees, file);
    fclose(file);
    printf("%d employee records written to binary file.\n\n", numEmployees);
    
    // Read employees from binary file
    file = fopen("employees.dat", "rb");
    if(file == NULL) {
        printf("Error opening file for reading!\n");
        return 1;
    }
    
    printf("Reading employee records:\n");
    printf("ID\tName\t\tSalary\t\tAge\n");
    printf("------------------------------------------------\n");
    
    while(fread(&empRead, sizeof(Employee), 1, file) == 1) {
        printf("%d\t%s\t%.2f\t%d\n", 
               empRead.id, empRead.name, empRead.salary, empRead.age);
    }
    fclose(file);
    
    // Random access: Read specific record
    printf("\nRandom access: Reading record #3 (index 2):\n");
    file = fopen("employees.dat", "rb");
    fseek(file, 2 * sizeof(Employee), SEEK_SET); // Move to 3rd record
    fread(&empRead, sizeof(Employee), 1, file);
    printf("Record #3: %d - %s - $%.2f - %d years old\n", 
           empRead.id, empRead.name, empRead.salary, empRead.age);
    fclose(file);
    
    // Get file size
    file = fopen("employees.dat", "rb");
    fseek(file, 0, SEEK_END);
    long fileSize = ftell(file);
    fclose(file);
    
    printf("\nFile size: %ld bytes\n", fileSize);
    printf("Size per employee: %lu bytes\n", sizeof(Employee));
    printf("Total employees in file: %ld\n", fileSize / sizeof(Employee));
    
    return 0;
}

File Error Handling

Proper error handling is crucial for robust file operations. Always check function return values and use error handling functions.

Example: Comprehensive Error Handling
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

int main() {
    FILE *sourceFile, *destFile;
    char sourceName[100], destName[100];
    char ch;
    
    printf("Enter source filename: ");
    scanf("%s", sourceName);
    printf("Enter destination filename: ");
    scanf("%s", destName);
    
    // Try to open source file
    sourceFile = fopen(sourceName, "r");
    if(sourceFile == NULL) {
        printf("Error opening source file '%s': %s\n", 
               sourceName, strerror(errno));
        return 1;
    }
    
    // Try to open destination file
    destFile = fopen(destName, "w");
    if(destFile == NULL) {
        printf("Error opening destination file '%s': %s\n", 
               destName, strerror(errno));
        fclose(sourceFile);
        return 1;
    }
    
    // Clear error indicators
    clearerr(sourceFile);
    clearerr(destFile);
    
    // Copy file content
    printf("Copying file...\n");
    while((ch = fgetc(sourceFile)) != EOF) {
        if(fputc(ch, destFile) == EOF) {
            if(ferror(destFile)) {
                printf("Error writing to destination file!\n");
                clearerr(destFile);
                break;
            }
        }
    }
    
    // Check for read errors
    if(ferror(sourceFile)) {
        printf("Error reading from source file!\n");
    }
    
    // Check for EOF
    if(feof(sourceFile)) {
        printf("File copied successfully. End of file reached.\n");
    }
    
    // Close files
    if(fclose(sourceFile) == EOF) {
        printf("Error closing source file!\n");
    }
    
    if(fclose(destFile) == EOF) {
        printf("Error closing destination file!\n");
    }
    
    // File operations
    printf("\nFile operations:\n");
    
    // Rename file
    if(rename("oldname.txt", "newname.txt") == 0) {
        printf("File renamed successfully.\n");
    } else {
        printf("Error renaming file: %s\n", strerror(errno));
    }
    
    // Delete file
    printf("Enter filename to delete: ");
    char deleteName[100];
    scanf("%s", deleteName);
    
    if(remove(deleteName) == 0) {
        printf("File '%s' deleted successfully.\n", deleteName);
    } else {
        printf("Error deleting file '%s': %s\n", deleteName, strerror(errno));
    }
    
    return 0;
}

Best Practices for File Handling

File Handling Best Practices:
  1. Always check fopen() return value: Never assume file opened successfully
  2. Close files properly: Always call fclose() to free resources and flush buffers
  3. Use appropriate file modes: Choose the right mode for your operation
  4. Check for EOF properly: Use feof() after read operations fail
  5. Handle errors gracefully: Provide meaningful error messages
  6. Use binary mode for structured data: Use "b" mode for arrays and structures
  7. Check write operations: Verify that write operations succeeded
  8. Use buffered I/O wisely: Large buffers for large files, small for small files
  9. Validate file names: Check for invalid characters in file names
  10. Clean up temporary files: Remove temporary files when done
Common Mistakes:
  • Not checking if fopen() returned NULL
  • Forgetting to close files (resource leak)
  • Using text mode for binary data (corruption)
  • Not handling partial read/write operations
  • Assuming file position after operations
  • Not clearing error indicators before reuse
  • Using gets() instead of fgets() for safety

Key Takeaways

  • File handling allows persistent data storage in C programs
  • Always use FILE pointers to work with files
  • Check fopen() return value for NULL before proceeding
  • Text files store human-readable data, binary files store raw bytes
  • Choose appropriate file modes (r, w, a, +, b combinations)
  • Use fclose() to close files and free resources
  • fread()/fwrite() for binary data, fprintf()/fscanf() for formatted text
  • Use fseek(), ftell(), rewind() for random file access
  • Implement error handling with feof(), ferror(), clearerr()
  • Follow best practices for robust and secure file operations
Next Topics: We'll explore command-line arguments.