Docs

File Handling

File Basics in C

Table of Contents

  1. β€’Introduction
  2. β€’What are Files?
  3. β€’File Types in C
  4. β€’File Pointer (FILE *)
  5. β€’Opening Files - fopen()
  6. β€’File Opening Modes
  7. β€’Closing Files - fclose()
  8. β€’Checking File Operations
  9. β€’File Handle and Streams
  10. β€’Standard Streams
  11. β€’File Operations Workflow
  12. β€’Common Pitfalls
  13. β€’Best Practices
  14. β€’Summary

Introduction

File handling is one of the most important aspects of programming. It allows programs to:

  • β€’Store data permanently - Data survives after program termination
  • β€’Process large datasets - Work with data too large for memory
  • β€’Share information - Exchange data between programs
  • β€’Maintain records - Create logs, configurations, databases
  • β€’Read external data - Process files created by other applications

C provides a comprehensive set of functions for file operations through the standard I/O library (<stdio.h>).


What are Files?

Definition

A file is a collection of related data stored on a secondary storage device (like a hard disk, SSD, or flash drive) with a unique name.

File Characteristics

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        FILE                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Name       : data.txt                                     β”‚
β”‚  Location   : /home/user/documents/                        β”‚
β”‚  Size       : 1024 bytes                                   β”‚
β”‚  Type       : Text file                                    β”‚
β”‚  Created    : 2024-01-15 10:30:00                         β”‚
β”‚  Modified   : 2024-01-20 15:45:00                         β”‚
β”‚  Permissions: Read, Write                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Why Use Files?

AspectWithout FilesWith Files
Data PersistenceLost when program endsSaved permanently
Data SizeLimited by RAMLimited by disk space
Data SharingDifficultEasy to share
Data ProcessingAll at onceCan process in chunks
Program StateLost on restartCan be restored

File Types in C

C distinguishes between two main types of files:

1. Text Files

  • β€’Store data as human-readable characters
  • β€’Each line typically ends with a newline character (\n)
  • β€’Data is stored as ASCII/UTF-8 characters
  • β€’Can be viewed with any text editor
  • β€’Slightly larger size due to character encoding
Example content of a text file:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Hello, World!                          β”‚
β”‚ This is line 2.                        β”‚
β”‚ Number: 42                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Characteristics:

  • β€’Portable across different systems
  • β€’Easy to read and edit
  • β€’Slower to process
  • β€’Newline conversion (CR/LF) may occur

2. Binary Files

  • β€’Store data in raw binary format
  • β€’Exact memory representation of data
  • β€’Cannot be read with text editors (appears garbled)
  • β€’More compact and efficient
  • β€’Faster to read/write
Example binary representation:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 48 65 6C 6C 6F 00 2A 00 00 00         β”‚
β”‚ (Hello + null + 42 as integer)         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Characteristics:

  • β€’More efficient storage
  • β€’Faster read/write operations
  • β€’Not human-readable
  • β€’May not be portable between systems

Comparison

FeatureText FileBinary File
ReadabilityHuman-readableMachine-readable
SizeLargerSmaller
SpeedSlowerFaster
PortabilityBetterSystem-dependent
Data TypesCharacter onlyAny data type
EditingEasyRequires special tools
Extension.txt, .csv, .c.bin, .dat, .exe

File Pointer (FILE *)

The FILE Structure

In C, file operations use a file pointer of type FILE *. The FILE structure is defined in <stdio.h> and contains information about the file being accessed.

#include <stdio.h>

FILE *fp;  // Declare a file pointer

What FILE Contains (Conceptual)

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     FILE Structure                          β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                        β”‚
β”‚  β”‚ Buffer Pointer  β”‚ β†’ Points to I/O buffer                 β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€                                        β”‚
β”‚  β”‚ Buffer Size     β”‚ β†’ Size of the buffer                   β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€                                        β”‚
β”‚  β”‚ Buffer Count    β”‚ β†’ Bytes remaining in buffer            β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€                                        β”‚
β”‚  β”‚ File Descriptor β”‚ β†’ OS-level file handle                 β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€                                        β”‚
β”‚  β”‚ Flags           β”‚ β†’ Read/Write/EOF/Error status          β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€                                        β”‚
β”‚  β”‚ File Position   β”‚ β†’ Current position in file             β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Important Points

  1. β€’Never access FILE members directly - Always use library functions
  2. β€’FILE * is opaque - Implementation details are hidden
  3. β€’Initialize to NULL - Good practice to initialize file pointers
  4. β€’Check for NULL - Always verify fopen() succeeded
FILE *fp = NULL;  // Good practice: initialize to NULL

fp = fopen("file.txt", "r");
if (fp == NULL) {
    // Handle error
    printf("Error: Cannot open file\n");
}

Opening Files - fopen()

Syntax

FILE *fopen(const char *filename, const char *mode);

Parameters

ParameterDescription
filenameName of the file (with optional path)
modeString specifying how to open the file

Return Value

  • β€’Success: Returns a pointer to FILE structure
  • β€’Failure: Returns NULL

Basic Usage

#include <stdio.h>

int main() {
    FILE *fp;

    // Open file for reading
    fp = fopen("myfile.txt", "r");

    if (fp == NULL) {
        printf("Error: Could not open file\n");
        return 1;
    }

    printf("File opened successfully!\n");

    // ... perform file operations ...

    fclose(fp);  // Always close the file
    return 0;
}

File Paths

// Current directory
fp = fopen("data.txt", "r");

// Relative path
fp = fopen("../data/input.txt", "r");
fp = fopen("subfolder/file.txt", "w");

// Absolute path (Linux/Mac)
fp = fopen("/home/user/documents/file.txt", "r");

// Absolute path (Windows)
fp = fopen("C:\\Users\\user\\Documents\\file.txt", "r");
// Or with forward slashes (works in Windows too)
fp = fopen("C:/Users/user/Documents/file.txt", "r");

File Opening Modes

Text Mode Options

ModeDescriptionFile ExistsFile Doesn't Exist
"r"Read onlyOpens fileReturns NULL
"w"Write onlyTruncates to 0Creates new file
"a"Append onlyOpens, position at endCreates new file
"r+"Read and writeOpens fileReturns NULL
"w+"Read and writeTruncates to 0Creates new file
"a+"Read and appendOpens fileCreates new file

Binary Mode Options

Add b to the mode string for binary files:

ModeDescription
"rb"Read binary
"wb"Write binary
"ab"Append binary
"rb+" or "r+b"Read and write binary
"wb+" or "w+b"Read and write binary (truncate)
"ab+" or "a+b"Read and append binary

Mode Behavior Visual

Mode "r" (Read):
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ existing content stays unchanged    β”‚
β”‚ ^                                   β”‚
β”‚ Position starts at beginning        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Cannot write, only read.

Mode "w" (Write):
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ (file is emptied/created)           β”‚
β”‚ ^                                   β”‚
β”‚ Position starts at beginning        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Previous content is LOST!

Mode "a" (Append):
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ existing content preserved          β”‚
β”‚                                    ^β”‚
β”‚ Position always at end for writing  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
New content added at end.

Mode "r+" (Read/Write):
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ existing content stays              β”‚
β”‚ ^                                   β”‚
β”‚ Can read and write anywhere         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Must call fseek() between read/write.

Mode "w+" (Read/Write, truncate):
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ (file is emptied/created)           β”‚
β”‚ ^                                   β”‚
β”‚ Can read and write                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Previous content is LOST!

Mode "a+" (Read/Append):
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ existing content preserved          β”‚
β”‚ ^                                   β”‚
β”‚ Can read from start, write at end   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Writes always go to end.

Choosing the Right Mode

Decision Tree:
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚ What operation?     β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β–Ό               β–Ό               β–Ό
         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”
         β”‚ Read   β”‚      β”‚ Write  β”‚      β”‚ Both   β”‚
         β””β”€β”€β”€β”¬β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”¬β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
             β”‚               β”‚               β”‚
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”
    β–Ό                 β–Ό     β”‚      β–Ό                 β–Ό
"r" or "rb"    File must   β”‚   Preserve        Truncate
   exist       exist?      β”‚   content?        content?
                           β”‚      β”‚                β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”     β–Ό                β–Ό
              β–Ό             β–Ό  "r+"/rb+"       "w+"/wb+"
         Create new    Truncate
         or append?    existing?
              β”‚             β”‚
        β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”      β–Ό
        β–Ό           β–Ό   "w"/"wb"
    "a"/"ab"   "w"/"wb"

Closing Files - fclose()

Syntax

int fclose(FILE *stream);

Return Value

  • β€’Success: Returns 0
  • β€’Failure: Returns EOF (typically -1)

Why Close Files?

  1. β€’Flush Buffers: Ensures all data is written to disk
  2. β€’Release Resources: Frees file handle and memory
  3. β€’Prevent Data Loss: Unsaved buffer data may be lost
  4. β€’Avoid File Limits: Systems limit open files
  5. β€’Allow Other Access: Release locks on the file

Basic Usage

#include <stdio.h>

int main() {
    FILE *fp = fopen("data.txt", "w");

    if (fp == NULL) {
        return 1;
    }

    fprintf(fp, "Hello, World!\n");

    // Close the file
    if (fclose(fp) != 0) {
        printf("Error closing file\n");
        return 1;
    }

    // Set pointer to NULL after closing (good practice)
    fp = NULL;

    return 0;
}

Common Mistakes with fclose()

// WRONG: Using file after closing
FILE *fp = fopen("test.txt", "r");
fclose(fp);
fgetc(fp);  // UNDEFINED BEHAVIOR!

// WRONG: Closing NULL pointer
FILE *fp = fopen("nonexistent.txt", "r");  // Returns NULL
fclose(fp);  // UNDEFINED BEHAVIOR!

// WRONG: Closing same file twice
FILE *fp = fopen("test.txt", "r");
fclose(fp);
fclose(fp);  // UNDEFINED BEHAVIOR!

// CORRECT approach:
FILE *fp = fopen("test.txt", "r");
if (fp != NULL) {
    // ... use file ...
    fclose(fp);
    fp = NULL;  // Prevent accidental reuse
}

Checking File Operations

Error Checking Pattern

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

int main() {
    FILE *fp;
    const char *filename = "data.txt";

    // Open file
    fp = fopen(filename, "r");

    if (fp == NULL) {
        // Method 1: Simple message
        printf("Error: Cannot open '%s'\n", filename);

        // Method 2: Using perror (prints system error message)
        perror("fopen failed");

        // Method 3: Using strerror
        printf("Error: %s\n", strerror(errno));

        return 1;
    }

    printf("File opened successfully\n");

    // Close file
    if (fclose(fp) == EOF) {
        perror("fclose failed");
        return 1;
    }

    return 0;
}

Common errno Values for File Operations

ErrorValueDescription
ENOENT2No such file or directory
EACCES13Permission denied
EEXIST17File exists (when creating)
EISDIR21Is a directory
EMFILE24Too many open files
ENOSPC28No space left on device
EROFS30Read-only file system

Using ferror() and feof()

#include <stdio.h>

void check_file_status(FILE *fp) {
    if (feof(fp)) {
        printf("End of file reached\n");
    }

    if (ferror(fp)) {
        printf("An error occurred\n");
        clearerr(fp);  // Clear error indicator
    }
}

File Handle and Streams

Buffering Concept

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      Buffered I/O                                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                  β”‚
β”‚   Program                Buffer                 Disk             β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”              β”Œβ”€β”€β”€β”€β”€β”€β”€β”              β”Œβ”€β”€β”€β”€β”€β”           β”‚
β”‚   β”‚     β”‚   write()    β”‚       β”‚   flush      β”‚     β”‚           β”‚
β”‚   β”‚     β”‚ ──────────► β”‚ ##### β”‚ ──────────► β”‚     β”‚           β”‚
β”‚   β”‚     β”‚              β”‚ ##### β”‚              β”‚     β”‚           β”‚
β”‚   β”‚     β”‚   read()     β”‚       β”‚   fill       β”‚     β”‚           β”‚
β”‚   β”‚     β”‚ ◄────────── β”‚ ##### β”‚ ◄────────── β”‚     β”‚           β”‚
β”‚   β””β”€β”€β”€β”€β”€β”˜              β””β”€β”€β”€β”€β”€β”€β”€β”˜              β””β”€β”€β”€β”€β”€β”˜           β”‚
β”‚                                                                  β”‚
β”‚   Data is collected in buffer before being written to disk.     β”‚
β”‚   This reduces the number of slow disk operations.              β”‚
β”‚                                                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Buffer Types

  1. β€’

    Fully Buffered: Data written when buffer is full

    • β€’Default for files
    • β€’Most efficient for files
  2. β€’

    Line Buffered: Data written when newline is encountered

    • β€’Default for terminals (stdout when connected to terminal)
    • β€’Good for interactive output
  3. β€’

    Unbuffered: Data written immediately

    • β€’Used for stderr
    • β€’Slower but immediate

Controlling Buffering

#include <stdio.h>

int main() {
    FILE *fp = fopen("output.txt", "w");

    // Set buffer size (must be called before any I/O)
    char buffer[1024];
    setvbuf(fp, buffer, _IOFBF, sizeof(buffer));  // Fully buffered

    // Or use setbuf
    // setbuf(fp, buffer);  // Enable buffering
    // setbuf(fp, NULL);    // Disable buffering

    // Alternative: use buffer modes
    // setvbuf(fp, NULL, _IONBF, 0);  // Unbuffered
    // setvbuf(fp, NULL, _IOLBF, 0);  // Line buffered
    // setvbuf(fp, NULL, _IOFBF, 0);  // Fully buffered (system size)

    fprintf(fp, "Data\n");

    fclose(fp);
    return 0;
}

Flushing the Buffer

#include <stdio.h>

int main() {
    FILE *fp = fopen("log.txt", "w");

    fprintf(fp, "Important message");

    // Force write to disk immediately
    fflush(fp);

    // ... program continues, data is safe on disk ...

    fclose(fp);
    return 0;
}

Standard Streams

C automatically opens three standard streams when a program starts:

The Three Standard Streams

StreamPointerDefaultPurpose
Standard InputstdinKeyboardRead user input
Standard OutputstdoutScreenNormal program output
Standard ErrorstderrScreenError messages
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      Standard Streams                           β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      stdin        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”                    β”‚
β”‚  β”‚ Keyboard β”‚ ────────────────► β”‚         β”‚                    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                   β”‚         β”‚                    β”‚
β”‚                                 β”‚ Program β”‚                    β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      stdout       β”‚         β”‚                    β”‚
β”‚  β”‚  Screen  β”‚ ◄──────────────── β”‚         β”‚                    β”‚
β”‚  β”‚          β”‚      stderr       β”‚         β”‚                    β”‚
β”‚  β”‚          β”‚ ◄──────────────── β”‚         β”‚                    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                    β”‚
β”‚                                                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Using Standard Streams

#include <stdio.h>

int main() {
    char name[50];

    // stdin - reading input
    fprintf(stdout, "Enter your name: ");  // Same as printf
    fscanf(stdin, "%49s", name);           // Same as scanf

    // stdout - normal output
    fprintf(stdout, "Hello, %s!\n", name); // Same as printf

    // stderr - error output
    fprintf(stderr, "Warning: This is an error message\n");

    return 0;
}

Redirecting Streams

# In shell/command line:

# Redirect stdout to file
./program > output.txt

# Redirect stderr to file
./program 2> errors.txt

# Redirect both
./program > output.txt 2> errors.txt

# Redirect stdin from file
./program < input.txt

# Combine all
./program < input.txt > output.txt 2> errors.txt

Reopening Standard Streams

#include <stdio.h>

int main() {
    // Redirect stdout to a file
    FILE *fp = freopen("output.txt", "w", stdout);

    if (fp == NULL) {
        fprintf(stderr, "Failed to redirect stdout\n");
        return 1;
    }

    // Now printf writes to file
    printf("This goes to output.txt\n");

    // Restore stdout (platform-specific)
    // On Linux: freopen("/dev/tty", "w", stdout);
    // On Windows: freopen("CON", "w", stdout);

    fclose(fp);
    return 0;
}

File Operations Workflow

Complete File Handling Pattern

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

int main() {
    FILE *fp = NULL;
    int result = 0;

    // Step 1: Open the file
    fp = fopen("data.txt", "r");
    if (fp == NULL) {
        perror("Error opening file");
        return EXIT_FAILURE;
    }

    // Step 2: Perform operations
    // ... read, write, or other operations ...

    // Step 3: Check for errors during operations
    if (ferror(fp)) {
        fprintf(stderr, "Error during file operations\n");
        result = EXIT_FAILURE;
    }

    // Step 4: Close the file
    if (fclose(fp) != 0) {
        perror("Error closing file");
        result = EXIT_FAILURE;
    }

    // Step 5: Nullify pointer
    fp = NULL;

    return result;
}

Workflow Diagram

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    File Operations Workflow                      β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                  β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                                β”‚
β”‚   β”‚   START     β”‚                                                β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜                                                β”‚
β”‚          β”‚                                                       β”‚
β”‚          β–Ό                                                       β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                    β”‚
β”‚   β”‚  fopen(file)    │─NO──►│ Handle Error  β”‚                    β”‚
β”‚   β”‚  fp != NULL?    β”‚      β”‚ (print, exit) β”‚                    β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                    β”‚
β”‚           β”‚YES                                                   β”‚
β”‚           β–Ό                                                      β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                            β”‚
β”‚   β”‚ Perform File    │◄──────────────────┐                       β”‚
β”‚   β”‚ Operations      β”‚                   β”‚                       β”‚
β”‚   β”‚ (read/write)    │────────────────────                       β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                   β”‚                       β”‚
β”‚           β”‚                             β”‚                       β”‚
β”‚           β–Ό                             β”‚                       β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       YES         β”‚                       β”‚
β”‚   β”‚  More ops?      β”‚β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                       β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                            β”‚
β”‚           β”‚NO                                                    β”‚
β”‚           β–Ό                                                      β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                    β”‚
β”‚   β”‚   fclose(fp)    │─ERR─►│ Handle Error  β”‚                    β”‚
β”‚   β”‚   == 0?         β”‚      β”‚ (log warning) β”‚                    β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜                    β”‚
β”‚           β”‚OK                      β”‚                            β”‚
β”‚           β–Ό                        β”‚                            β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”              β”‚                            β”‚
β”‚   β”‚   fp = NULL     β”‚β—„β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                            β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                            β”‚
β”‚           β”‚                                                      β”‚
β”‚           β–Ό                                                      β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                                β”‚
β”‚   β”‚    END      β”‚                                                β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                                β”‚
β”‚                                                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Common Pitfalls

1. Not Checking fopen() Return Value

// WRONG - dangerous!
FILE *fp = fopen("file.txt", "r");
fprintf(fp, "data");  // CRASH if file doesn't exist!

// CORRECT
FILE *fp = fopen("file.txt", "r");
if (fp == NULL) {
    perror("Cannot open file");
    return 1;
}
fprintf(fp, "data");

2. Forgetting to Close Files

// WRONG - resource leak
void process_files() {
    for (int i = 0; i < 1000; i++) {
        char filename[50];
        sprintf(filename, "file%d.txt", i);
        FILE *fp = fopen(filename, "r");
        // ... process ...
        // Forgot fclose(fp)!  // Eventually runs out of file handles
    }
}

// CORRECT
void process_files() {
    for (int i = 0; i < 1000; i++) {
        char filename[50];
        sprintf(filename, "file%d.txt", i);
        FILE *fp = fopen(filename, "r");
        if (fp != NULL) {
            // ... process ...
            fclose(fp);
        }
    }
}

3. Using Wrong Mode

// WRONG - "w" destroys existing content!
FILE *fp = fopen("important_data.txt", "w");  // File is now EMPTY!

// CORRECT - use "a" to append or "r+" to modify
FILE *fp = fopen("important_data.txt", "a");  // Adds to existing
// OR
FILE *fp = fopen("important_data.txt", "r+"); // Read/write without truncating

4. Mixing Text and Binary Modes

// WRONG - writing binary data in text mode
struct Data { int x; float y; } data = {42, 3.14};
FILE *fp = fopen("data.dat", "w");  // Text mode!
fwrite(&data, sizeof(data), 1, fp);  // May corrupt on Windows

// CORRECT - use binary mode for binary data
FILE *fp = fopen("data.dat", "wb");  // Binary mode
fwrite(&data, sizeof(data), 1, fp);

5. Not Handling Paths Correctly

// Platform-specific issues
// Windows uses backslashes, Linux uses forward slashes

// PORTABLE approach - use forward slashes (works on both)
FILE *fp = fopen("data/input/file.txt", "r");

// Or use path construction
char path[256];
snprintf(path, sizeof(path), "data%cinput%cfile.txt",
         '/', '/');  // Use '/' for portability

Best Practices

1. Always Check Return Values

FILE *fp = fopen(filename, "r");
if (fp == NULL) {
    // Handle error appropriately
    perror("Failed to open file");
    return -1;
}

2. Use Meaningful Variable Names

// POOR
FILE *f;

// BETTER
FILE *inputFile;
FILE *outputFile;
FILE *configFile;

3. Close Files as Soon as Possible

// Read all data, then close
FILE *fp = fopen("data.txt", "r");
if (fp != NULL) {
    // Read all needed data
    char buffer[1000];
    fgets(buffer, sizeof(buffer), fp);

    // Close immediately after reading
    fclose(fp);
    fp = NULL;

    // Process data (file is already closed)
    process(buffer);
}

4. Use Helper Functions

// Create reusable file opening function
FILE *open_file_safe(const char *filename, const char *mode) {
    FILE *fp = fopen(filename, mode);
    if (fp == NULL) {
        fprintf(stderr, "Error: Cannot open '%s' with mode '%s': %s\n",
                filename, mode, strerror(errno));
    }
    return fp;
}

// Usage
FILE *fp = open_file_safe("data.txt", "r");
if (fp != NULL) {
    // ... use file ...
    fclose(fp);
}

5. Consider Using goto for Cleanup

int process_file(const char *filename) {
    FILE *fp = NULL;
    char *buffer = NULL;
    int result = -1;

    fp = fopen(filename, "r");
    if (fp == NULL) goto cleanup;

    buffer = malloc(1000);
    if (buffer == NULL) goto cleanup;

    // ... process ...

    result = 0;  // Success

cleanup:
    if (buffer != NULL) free(buffer);
    if (fp != NULL) fclose(fp);
    return result;
}

Summary

Key Concepts

ConceptDescription
FILE *Pointer to file structure, used for all operations
fopen()Opens a file, returns FILE * or NULL
fclose()Closes a file, flushes buffers, returns 0 or EOF
Modes"r", "w", "a", "r+", "w+", "a+" (add "b" for binary)
Streamsstdin, stdout, stderr are predefined FILE pointers
BufferingData collected in memory before disk operations

Mode Quick Reference

ModeExistsNot ExistsPositionTruncate
rReadErrorStartNo
wWriteCreateStartYes
aWriteCreateEndNo
r+R/WErrorStartNo
w+R/WCreateStartYes
a+R/WCreateEnd(w)No

Essential Error Checking

// Minimal safe pattern
FILE *fp = fopen("file.txt", "r");
if (fp == NULL) {
    perror("fopen");
    return 1;
}

// ... operations ...

if (fclose(fp) != 0) {
    perror("fclose");
    return 1;
}

What's Next?

In the following sections, we'll explore:

  • β€’Reading from files (fgetc, fgets, fscanf, fread)
  • β€’Writing to files (fputc, fputs, fprintf, fwrite)
  • β€’File positioning (fseek, ftell, rewind)
  • β€’Binary file operations
  • β€’Error handling and file status

Practice Exercises Preview

  1. β€’Open a file and check if it exists
  2. β€’Create a new file with sample content
  3. β€’Handle file opening errors gracefully
  4. β€’Work with different file modes
  5. β€’Redirect stdout to a file
File Handling - C Programming Tutorial | DeepML