File Handling (Lesson)

File Handling in C

In C programming, a file is a place on the disk where a group of related data is stored. File handling allows you to create, update, read, and delete the data stored in files.

1. Why do we need Files?

  • Data Persistence: When a program terminates, the data in variables is lost. Storing data in a file preserves it for future use.
  • Handling Large Data: Entering thousands of records manually every time a program runs is inefficient. Files allow you to read bulk data instantly.
  • Portability: You can easily transfer files from one computer to another without changing the program logic.

2. Types of Files

In C, you can deal with two main types of files:

A. Text Files (.txt)

  • Store data in plain text (ASCII/Unicode).
  • Can be opened and read using any text editor (Notepad, VS Code).
  • Pros: Easy to maintain, readable, and portable across platforms.
  • Cons: Less secure and takes up more storage space.

B. Binary Files (.bin, .dat)

  • Store data in binary format (0s and 1s), exactly as it appears in memory.
  • Cannot be read easily with standard text editors.
  • Pros: High storage efficiency, better security, and faster access for large datasets.
  • Cons: Not human-readable without a specialized program.

3. Working with Files

To work with files, you must declare a pointer of type FILE. This pointer acts as a bridge between the program and the file stored on the disk.

FILE *fp;

3.1. Opening and Closing a File

  • Opening: fp = fopen("filename", "mode");
  • Closing: fclose(fp); (Always close files to release memory resources).

File Modes

ModeMeaningExplanation
"r"/"rb"ReadOpens a text/binary file for reading. Returns NULL if not found.
"w"/"wb"WriteCreates a file or overwrites an existing one for writing.
"a"/"ab"AppendOpens or creates a file for adding data at the end.
"r+"/"rb+"Read/WriteOpens for both reading and writing.

4. Reading and Writing to Files

4.1. Text File I/O (fprintf & fscanf)

These functions are similar to printf and scanf, but they work with files.

Example: Writing a number to a file

#include <stdio.h>
#include <stdlib.h>

int main() {
    int num;
    FILE *fptr = fopen("program.txt", "w");

    if (fptr == NULL) {
        printf("Error! File could not be opened.");
        exit(1);
    }

    printf("Enter a number: ");
    scanf("%d", &num);
    fprintf(fptr, "%d", num);
    
    fclose(fptr);
    return 0;
}

4.2. Binary File I/O (fwrite & fread)

Binary files use fwrite and fread to store and retrieve entire blocks of memory (like structures).

Syntax:

fwrite(address_of_data, size_of_data, number_of_records, file_pointer);
fread(address_to_store, size_of_data, number_of_records, file_pointer);

Example: Storing a Structure

#include <stdio.h>

struct Record {
    int id;
    char name[20];
};

int main() {
    FILE *fp = fopen("data.bin", "wb");
    struct Record r1 = {1, "Project A"};
    
    fwrite(&r1, sizeof(struct Record), 1, fp);
    fclose(fp);
    return 0;
}

5. Random Access in Files (fseek, ftell, rewind)

Sometimes, instead of reading a file from the beginning, you need to jump to a specific record.

  • fseek(): Moves the file pointer to a specific location.
    • fseek(fp, offset, SEEK_SET); // Start from beginning
    • fseek(fp, offset, SEEK_CUR); // Start from current position
    • fseek(fp, offset, SEEK_END); // Start from end
  • ftell(): Tells you the current position of the pointer (in bytes).
  • rewind(): Quickly moves the pointer back to the very beginning.

Example: Reading Records in Reverse

#include <stdio.h>
#include <stdlib.h>

struct Data {
    int n1;
};

int main() {
    FILE *fptr = fopen("numbers.bin", "rb");
    struct Data d;

    // Move to the very last record
    fseek(fptr, -sizeof(struct Data), SEEK_END);
    
    // Read and then move back two steps to simulate reverse reading
    for(int i = 0; i < 5; ++i) {
        fread(&d, sizeof(struct Data), 1, fptr);
        printf("Value: %d\n", d.n1);
        fseek(fptr, -2 * sizeof(struct Data), SEEK_CUR);
    }

    fclose(fptr);
    return 0;
}

7. Practical Examples & Mini-Projects

Here are several practical scenarios to help you master file handling.

Example A: Counting Characters, Words, and Lines

This program reads a text file and counts its contents. This is a common logic used in text editors.

#include <stdio.h>

int main() {
    FILE *fp;
    char ch;
    int chars = 0, words = 0, lines = 0;

    fp = fopen("article.txt", "r");
    if (fp == NULL) return 1;

    while ((ch = fgetc(fp)) != EOF) {
        chars++;
        if (ch == '\n' || ch == '\0') lines++;
        if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\0') words++;
    }

    if (chars > 0) {
        lines++; // Count the last line
        words++; // Count the last word
    }

    printf("Characters: %d\n", chars);
    printf("Words: %d\n", words);
    printf("Lines: %d\n", lines);

    fclose(fp);
    return 0;
}

Example B: Copying One File to Another

A simple "file cloning" program. It reads from a source and writes to a destination.

#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE *source, *dest;
    char ch;

    source = fopen("source.txt", "r");
    if (source == NULL) exit(1);

    dest = fopen("destination.txt", "w");
    if (dest == NULL) {
        fclose(source);
        exit(1);
    }

    while ((ch = fgetc(source)) != EOF) {
        fputc(ch, dest);
    }

    printf("File copied successfully.\n");

    fclose(source);
    fclose(dest);
    return 0;
}

Example C: Appending Data (The "Logger" Pattern)

This example shows how to add data to the end of a file without deleting the old content using "a" mode.

#include <stdio.h>
#include <time.h>

int main() {
    FILE *logFile;
    logFile = fopen("log.txt", "a");

    if (logFile == NULL) return 1;

    // Get current time
    time_t now = time(NULL);
    char *time_str = ctime(&now);

    fprintf(logFile, "Program accessed at: %s", time_str);
    printf("Access time logged.\n");

    fclose(logFile);
    return 0;
}

8. Persistence Mini-Project: Student Database

This example demonstrates a tiny database where you can add records and then view them all later.

#include <stdio.h>

struct Student {
    int id;
    char name[30];
    float marks;
};

void addRecord() {
    FILE *fp = fopen("students.db", "ab");
    struct Student s;

    printf("Enter ID, Name, and Marks: ");
    scanf("%d %s %f", &s.id, s.name, &s.marks);

    fwrite(&s, sizeof(struct Student), 1, fp);
    fclose(fp);
}

void displayRecords() {
    FILE *fp = fopen("students.db", "rb");
    struct Student s;

    printf("\n--- Student List ---\n");
    while (fread(&s, sizeof(struct Student), 1, fp)) {
        printf("ID: %d | Name: %-10s | Marks: %.2f\n", s.id, s.name, s.marks);
    }
    fclose(fp);
}

int main() {
    int choice;
    while(1) {
        printf("\n1. Add Record\n2. Display All\n3. Exit\nChoice: ");
        scanf("%d", &choice);
        if(choice == 1) addRecord();
        else if(choice == 2) displayRecords();
        else break;
    }
    return 0;
}
PREVIOUS
Structures
FINISH
Back to Course Overview