C

Reading and Writing Files in C Programming

File handling in C allows you to store data permanently on a storage device. When a program terminates, the data in the RAM is lost; however, by writing to a file, you preserve that data. Conversely, reading from a file allows your program to load previously saved data into the workspace.

In C, all file input and output (I/O) is handled through a sequence of bytes known as a Stream.

1. The Theory: Text vs. Binary Streams

Before performing read/write operations, you must decide how the data should be interpreted.

A. Text Files (.txt, .c, .csv)

  • Theory: Data is stored as a sequence of characters (ASCII or UTF-8).

  • Newline Translation: In text mode, special characters like the newline \n might be translated into system-specific formats (e.g., CRLF on Windows).

  • Usage: Best for data that needs to be human-readable.

B. Binary Files (.bin, .dat, .exe)

  • Theory: Data is stored exactly as it appears in the computer's memory (raw bytes).

  • No Translation: No transformation occurs; what is in RAM is mirrored on the disk.

  • Usage: Best for complex data types like structures, arrays, or images. It is more space-efficient and faster than text mode.

2. Standard Functions for Reading and Writing

The <stdio.h> library provides several levels of functions depending on whether you want to process data character-by-character, line-by-line, or in formatted blocks.

A. Formatted I/O: fprintf() and fscanf()

These behave exactly like printf and scanf, but they operate on a file instead of the console.

  • fprintf(fp, "format", ...): Writes formatted text to the file.

  • fscanf(fp, "format", ...): Reads formatted text from the file into variables.

B. Character I/O: fputc() and fgetc()

Used for processing files one character at a time.

  • fgetc(fp): Reads the next character. Returns EOF (End of File) when the end is reached.

  • fputc(char, fp): Writes a single character to the file.

C. Line I/O: fputs() and fgets()

Used for processing strings or entire lines.

  • fgets(buffer, size, fp): Reads a string until a newline or size-1 characters are reached. It is safer than fscanf for strings because it prevents buffer overflows.

3. The Lifecycle of a File Operation

Every read/write operation follows a strict four-step theory:

  1. Pointer Declaration: Create a FILE *fp; to keep track of the file.

  2. Opening: Use fopen() to link the pointer to a physical file and define the intent (Read, Write, or Append).

  3. Processing: Use the functions mentioned above to move data between RAM and Disk.

  4. Closing: Use fclose() to break the link and "flush" the buffer.

4. Practical Code Example: Writing and Reading Text

This example demonstrates creating a file, writing a user's input to it, and then reading it back to display on the screen.

#include <stdio.h>

int main() {
    FILE *fptr;
    char text[100];

    // --- WRITING SECTION ---
    // Open for writing ("w"). If file exists, it is overwritten.
    fptr = fopen("emblab_notes.txt", "w");

    if (fptr == NULL) {
        printf("Error opening file for writing!\n");
        return 1;
    }

    printf("Enter a sentence to save to the file: ");
    fgets(text, sizeof(text), stdin);

    fprintf(fptr, "User Note: %s", text);
    fclose(fptr); // Closing saves the data to disk
    printf("Data saved successfully.\n\n");

    // --- READING SECTION ---
    // Open for reading ("r").
    fptr = fopen("emblab_notes.txt", "r");

    if (fptr == NULL) {
        printf("Error opening file for reading!\n");
        return 1;
    }

    printf("Reading from file...\nContent: ");
    // Read the file line by line until End of File (EOF)
    while (fgets(text, sizeof(text), fptr) != NULL) {
        printf("%s", text);
    }

    fclose(fptr);
    return 0;
}

5. Advanced Theory: The File Position Indicator

Internally, the FILE structure maintains a "cursor" called the File Position Indicator.

  • When you open a file in "r" or "w" mode, the cursor starts at the very beginning (byte 0).

  • When you open in "a" (append) mode, the cursor starts at the end.

  • Every time you read or write a byte, the cursor moves forward automatically.

You can manually manipulate this cursor using fseek() and ftell(), allowing for "Random Access"—reading the 100th record without reading the first 99.

6. Common Pitfalls to Avoid

  1. Ignoring the Return of fopen: If you try to read a file that doesn't exist, fopen returns NULL. Trying to read from a NULL pointer will crash your program.

  2. Forgetting to fclose: If you don't close a file after writing, the last few bytes of your data might stay in the memory buffer and never actually reach the hard drive.

  3. The fscanf Space Problem: Like scanf, fscanf stops reading at the first space. For sentences, always use fgets.

Upcoming Course
Upcoming Course
Learn More
Instructor Tips
Instructor Tips
View Tips
Join Community
Join Community
Join Now