Skip to main content

File Handling in C: fopen, fclose, fprintf, fscanf, fread, fwrite 💾

File Handling in C: fopen, fclose, fprintf, fscanf, fread, fwrite is a core C concept covering master C File Handling. Learn the FILE pointer, fopen modes, text I/O (fprintf/fscanf) vs binary I/O (fread/fwrite), error checks, and EOF handling. This topic is essential for academic learning, board exam preparation, and developing optimized real-world code.

Mentor's Note: Think of your computer's RAM as a whiteboard. You write numbers on it, but the moment you turn off the computer (or the program terminates), the whiteboard is wiped clean. If you want your data to survive, you must write it down in a notebook (Hard Drive/SSD). In C, file handling functions are the pens that allow you to read and write to this permanent notebook! 💡

📚 Educational Content: File Handling is a critical module in Board Exams (GSEB/CBSE Class 12) and university exams (BCA Sem 1 / BE). Theory questions focus on "Text vs Binary Files", "File Opening Modes", and debugging code blocks that fail to handle file-not-found exceptions.

:::info What You'll Learn By the end of this tutorial, you'll know:

  • What a FILE* pointer is and how streams operate.
  • The various file opening modes (r, w, a, rb, wb, etc.).
  • How to write and read text using fprintf() and fscanf().
  • How to write and read structures directly using binary fwrite() and fread().
  • The common bugs involving feof() and how to check for end-of-file safely.
  • A fully functional save/load implementation for a student database. :::

🌟 The Scenario: The Vanishing Database

Imagine you write a beautiful Student Management Program:

  • You input details for 50 students, calculate their grades, and view their cards.
  • The Logic: All this data lives in RAM. When you close the program or shut down the PC: RAM power goes off ➔ Data disappears
  • The Result: You lose all student records! To prevent this, you save the student arrays into a binary file students.dat before closing. The next time the program starts, it loads the data back into memory. ✅

📖 Concept Explanation

File handling in C centers around the standard library stream pointer, FILE *. This pointer tracks the file location on the disk, the read/write cursor position, and error status flags.

1. File Opening (fopen) and Closing (fclose)

We open files using fopen(), which returns a FILE * handle.

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

So what? If the file doesn't exist or is locked, fopen returns NULL. You must check for this, or dereferencing it will crash your program.

When finished, always release the file handle:

fclose(fp);

So what? Closing a file flushes any pending writes from RAM buffers onto the physical disk and frees the operating system file locks.

2. File Opening Modes

ModeTypeAction if File ExistsAction if File Does Not Exist
"r"Text (Read)Opens for reading.Returns NULL.
"w"Text (Write)Overwrites / truncates content.Creates new file.
"a"Text (Append)Appends data at the end.Creates new file.
"rb"Binary (Read)Opens binary file for reading.Returns NULL.
"wb"Binary (Write)Overwrites binary file.Creates new file.

3. Text vs Binary File I/O

  • Text Mode (fprintf / fscanf): Data is written as human-readable ASCII text characters. So what? Newline characters (\n) are automatically converted to match the operating system's standard (e.g. \r\n on Windows).
  • Binary Mode (fwrite / fread): Data is written as raw bytes from memory. So what? It is faster, uses less disk space, and allows saving complex data types like structs in a single call.
// Binary Write Syntax
fwrite(&my_struct, sizeof(my_struct), 1, fp);

4. The feof() Trap

A common bug is writing while(!feof(fp)) to read files.

So what? The end-of-file flag is only set after a read operation has failed. If you use while(!feof(fp)), the loop will run one extra time, processing duplicate or garbage values at the end of the file. The correct way is checking the return value of your read functions (like fscanf or fread).


🧠 Step-by-Step Logic

Let's design a system to save and load student data:

  1. Start 🏁
  2. Define a Student structure.
  3. Open a file students.bin in binary write (wb) mode.
  4. Check if file pointer is NULL. If yes, terminate.
  5. Write the records using fwrite(). Close file.
  6. Open the file in binary read (rb) mode.
  7. Read records using fread() in a loop until read count is less than 1.
  8. Display the loaded records. Close file.
  9. End 🏁

💻 C Implementation (C99)

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

typedef struct {
int roll_no;
char name[50];
float gpa;
} Student;

// Function declarations
void saveRecords(const char *filename, const Student *list, int count);
void loadRecords(const char *filename);

int main() {
// 🛒 Scenario: Persistent Student Database
// 🚀 Action: Write struct array to file and read it back

const char *db_file = "students.bin";

Student school_list[3] = {
{101, "Aarav Mehta", 9.2},
{102, "Diya Patel", 8.8},
{103, "Kabir Shah", 9.5}
};

printf("--- Saving records to file ---\n");
saveRecords(db_file, school_list, 3);

printf("\n--- Loading and displaying records ---\n");
loadRecords(db_file);

return 0;
}

// Function to save records using fwrite (Binary Write)
void saveRecords(const char *filename, const Student *list, int count) {
FILE *fp = fopen(filename, "wb"); // Open in binary write

if (fp == NULL) {
perror("Error opening file for writing");
exit(1);
}

// Write entire array of structs in a single instruction
size_t written = fwrite(list, sizeof(Student), count, fp);
printf("Successfully wrote %lu student records.\n", written);

fclose(fp); // Close to flush buffer
}

// Function to read records using fread (Binary Read)
void loadRecords(const char *filename) {
FILE *fp = fopen(filename, "rb"); // Open in binary read

if (fp == NULL) {
perror("Error opening file for reading");
exit(1);
}

Student temp;
// Read one structure at a time until end-of-file is hit
// fread returns the number of objects successfully read
while (fread(&temp, sizeof(Student), 1, fp) == 1) {
printf("Roll: %d | Name: %-15s | GPA: %.2f\n",
temp.roll_no, temp.name, temp.gpa);
}

fclose(fp);
}

// Output:
// --- Saving records to file ---
// Successfully wrote 3 student records.
//
// --- Loading and displaying records ---
// Roll: 101 | Name: Aarav Mehta | GPA: 9.20
// Roll: 102 | Name: Diya Patel | GPA: 8.80
// Roll: 103 | Name: Kabir Shah | GPA: 9.50

📊 Sample Dry Run

Let's trace the file reading loop inside loadRecords():

Loop IterationPosition in File (Bytes)fread() Return ValueDestination Struct tempAction taken
Start0--File opened successfully
10561{101, "Aarav Mehta", 9.2}Printed successfully ✅
2561121{102, "Diya Patel", 8.8}Printed successfully ✅
31121681{103, "Kabir Shah", 9.5}Printed successfully ✅
41680 (EOF hit)-Loop terminates safely

📉 Complexity Analysis

Time Complexity ⏱️

  • Binary I/O Operations: $O(N)$ where $N$ is the number of records read or written.
  • Disk Latency: Reading from disk is thousands of times slower than reading from RAM. Minimizing file open/close counts is recommended.

Space Complexity 💾

  • RAM footprint: $O(1)$ auxiliary space during read loops (uses a single buffer struct variable).
  • Disk footprint: O(N * sizeof(struct)) bytes.

🎯 Practice Problems

Easy Level 🟢

  1. Write a program to read a text file notes.txt character by character using fgetc() and display the output on the terminal.

Medium Level 🟡

  1. Write a program to copy the contents of one text file to another, while converting all lowercase letters to uppercase letters in the process.

Hard Level 🔴

  1. Create a library management application. Define a structure Book (BookID, Title, Status). Write functions that allow:
    • Adding a new book record (append).
    • Displaying all books (read).
    • Updating the Status (Issued/Available) of a book matching a specific BookID (requires reading, modifying, and rewriting).

❓ Frequently Asked Questions

Q: What is the difference between text mode ("w") and binary mode ("wb")?

In text mode, system-specific conversions happen (e.g. \n translates to \r\n on Windows). In binary mode, memory contents are written directly to disk bit-by-bit without translation, ensuring compatibility.

Q: Why should we never check while(!feof(fp)) directly?

feof() returns true only after a read operation fails. In while(!feof(fp)), the loop runs even when the file pointer is at EOF. The final read operation fails, but the loop logic executes one more time using old buffer data.

Q: What is the purpose of fflush()?

fflush(FILE *stream) forces the system to write any buffered output data in memory to the physical disk immediately, without waiting for the file to close.


📚 Best Practices & Common Mistakes

✅ Best Practices

  • Always Check NULL: Always verify if fopen returned NULL before reading or writing. Failing to check causes immediate crashes.
  • Always Close Streams: Close all files using fclose to prevent memory leaks and file corruption issues.
  • Check Return Values: Inspect fread and fwrite return counts to confirm all operations succeeded.

❌ Common Mistakes ⚠️

  • Invalid Path Slash: Using single backslashes in paths on Windows (e.g. fopen("c:\temp\data.txt", "r")). You must write double backslashes \\ (e.g., "c:\\temp\\data.txt") or use forward slashes /.
  • Wrong Mode Overwrites: Opening a file in "w" mode when you intend to add records. "w" truncates the file immediately, deleting all existing records. Use "a" or "r+" instead.

✅ Summary

In this tutorial, you've learned:

  • ✅ Files allow storing data permanently on storage devices.
  • ✅ The FILE * pointer tracks file information and stream properties.
  • ✅ Opening files requires checking for NULL to prevent program crashes.
  • ✅ Binary operations (fread/fwrite) are faster and handle structure variables seamlessly.
  • ✅ Loop checks should inspect read execution success counts instead of using feof().

💡 Interview Tips & Board Focus 👔

  • Text vs Binary: Frequently asked in practical viva examinations. Focus on the raw byte nature of binary files.
  • feof() Bug Explanation: Explain why checking return value is safer. This shows standard coding habits.

📚 Further Reading

Continue your learning path:


📍 Visit Us

🏫 VD Computer Tuition Surat

VD Computer Tuition
📍 Address
2/66 Faram Street, Rustompura
Surat395002, Gujarat, India
📞 Phone / WhatsApp
+91 84604 41384
🌐 Website

Computer Classes & Tuition — Areas We Serve in Surat

AdajanAlthanAmroliAthwaAthwalinesBhagalBhatarBhestanCanal RoadChowkCitylightDumasGaurav PathGhod Dod RoadHaziraJahangirpuraKamrejKapodraKatargamLimbayatMagdallaMajura GateMota VarachhaNanpuraNew CitylightOlpadPalPandesaraParle PointPiplodPunaRanderRing RoadRustampuraSachinSalabatpuraSarthanaSosyo CircleUdhnaVarachhaVed RoadVesuVIP Road
📞 Call Sir💬 WhatsApp Sir