Object Oriented ProgrammingUnit 814 min read
File Handling in C++: Streams, File Operations & Error Handling
Unit 8 of Object Oriented Programming: Explores C++ file handling using streams (ifstream, ofstream, fstream), file operations (reading/writing text/binary), error handling, and real-world applications like data persistence in apps, transaction logs, and user-generated content storage.
TAKEAWAYS:
- File handling in C++ uses streams (
ifstream,ofstream,fstream) to read/write data sequentially, enabling persistent storage of program data. - Text files store data as ASCII/Unicode characters, while binary files store raw bytes (e.g., images, serialized objects) for faster access and space efficiency.
- Error handling (e.g.,
fail(),eof(),bad()) ensures robustness when files are missing, corrupted, or inaccessible. - Common operations include opening/closing files, sequential/random access, and appending data, critical for logging, databases, and user data.
- Real-world use: Apps like eSewa store transaction logs in files, Daraz saves order histories, and NTC manages call records—all using file handling.
- Memory management is implicit in file streams (auto-closed on destruction), but explicit
close()improves performance for large files.
1. Introduction to File Handling
File handling allows programs to store and retrieve data permanently, even after termination. Unlike variables (stored in RAM), files persist on secondary storage (SSD/HDD). Key concepts:
- File: A named collection of data stored on disk.
- Stream: A sequence of bytes (text/binary) flowing into/out of a file (or device like keyboard/monitor).
- File Operations: Open, read, write, append, close, seek (random access).
1.1 Streams in C++
C++ uses stream classes from <fstream> to interact with files:
classDiagram
class Stream {
+open() string
+close()
+read() char
+write() char
+eof() bool
+fail() bool
}
class ifstream {
+read text files
}
class ofstream {
+write text files
}
class fstream {
+read/write text/binary
}
Stream <|-- ifstream
Stream <|-- ofstream
Stream <|-- fstreamKey Stream Classes:
| Class | Purpose | Example Usage |
|---|---|---|
ifstream |
Read-only text files | ifstream fin("data.txt"); |
ofstream |
Write-only text files | ofstream fout("output.txt"); |
fstream |
Read/write text/binary files | fstream file("data.bin", ios::binary); |
1.2 Opening and Closing Files
Opening: Use
open(filename, mode)or constructor syntax.ifstream fin("input.txt"); // Default: text mode, read-only ofstream fout("output.txt", ios::app); // Append modeModes:
ios::in: Open for input (default forifstream).ios::out: Open for output (default forofstream).ios::app: Append to end of file.ios::trunc: Truncate file before opening (default forofstream).ios::binary: Binary mode (no text mode conversions).
Closing: Files auto-close when stream object is destroyed, but explicit
close()is better for large files.fin.close(); // Good practice
1.3 Checking File Status
Use member functions to verify file operations:
graph TD
A["File Operation"] --> B{"fail()"}
B -->|"true"| C["Error occurred"]
B -->|"false"| D{"good()"}
D -->|"true"| E["Operation succeeded"]
D -->|"false"| F{"eof()"}
F -->|"true"| G["End of file reached"]
F -->|"false"| H["Data available"]
E -->|"Check with"| I["!fail() && good()"]
caption "Status checking flow in C++ file streams"Example:
ifstream fin("data.txt");
if (!fin.is_open()) {
cerr << "Error opening file!" << endl;
return 1;
}
2. Reading from Files
2.1 Reading Text Files
Use >> operator to read line-by-line or character-by-character.
Example: Read a Text File
#include <fstream>
#include <iostream>
using namespace std;
int main() {
ifstream fin("students.txt");
if (!fin.is_open()) {
cerr << "Failed to open file!" << endl;
return 1;
}
string line;
while (getline(fin, line)) { // Read entire line
cout << line << endl;
}
fin.close();
return 0;
}
Trace:
| Step | Action | State of fin |
|---|---|---|
| 1 | fin.open("students.txt") |
File opened, pointer at start |
| 2 | getline(fin, line) |
Reads "Alice,20" → line = "Alice,20" |
| 3 | getline(fin, line) |
Reads "Bob,21" → line = "Bob,21" |
| 4 | fin.eof() |
Returns true (end of file) |
2.2 Reading Binary Files
Binary files store raw bytes (e.g., serialized objects). Use read() or write() with ios::binary.
Example: Read Binary Data
#include <fstream>
struct Student {
char name[50];
int age;
};
int main() {
ifstream fin("students.dat", ios::binary);
Student s;
while (fin.read(reinterpret_cast<char*>(&s), sizeof(s))) {
cout << s.name << ", " << s.age << endl;
}
fin.close();
return 0;
}
Visualization:
Binary File Structure:
+---------------------+---------------------+
| Student 1 (Alice) | Student 2 (Bob) |
| [Name: Alice, Age:20]| [Name: Bob, Age:21] |
+---------------------+---------------------+
3. Writing to Files
sequenceDiagram
participant Program
participant File
Program->>File: fout.open("output.txt")
File-->>Program: File opened
Program->>File: fout << "Hello, File Handling!"
Program->>File: fout << "\nLine 2"
Program->>File: fout.close()
File-->>Program: File persisted
caption "Step-by-step writing process to output.txt"3.1 Writing Text Files
Use << operator to write data sequentially.
Example: Write to a Text File
#include <fstream>
#include <iostream>
using namespace std;
int main() {
ofstream fout("output.txt");
if (!fout.is_open()) {
cerr << "Failed to open file!" << endl;
return 1;
}
fout << "Hello, File Handling!" << endl;
fout << "Line 2" << endl;
fout.close();
return 0;
}
State After Writing:
File "output.txt":
Hello, File Handling!
Line 2
3.2 Writing Binary Files
Use write() to store structured data (e.g., objects).
Example: Write Binary Data
#include <fstream>
struct Student {
char name[50];
int age;
};
int main() {
ofstream fout("students.dat", ios::binary);
Student s1 = {"Alice", 20};
Student s2 = {"Bob", 21};
fout.write(reinterpret_cast<char*>(&s1), sizeof(s1));
fout.write(reinterpret_cast<char*>(&s2), sizeof(s2));
fout.close();
return 0;
}
Binary File Layout:
+-----------+-----------+-----------+-----------+
| Alice (50)| 20 (int) | Bob (50) | 21 (int) |
+-----------+-----------+-----------+-----------+
4. Random Access in Files
Use seekg() (input) and seekp() (output) to navigate files.
Example: Jump to Position
#include <fstream>
int main() {
fstream file("data.bin", ios::in | ios::out | ios::binary);
file.seekg(0, ios::end); // Move to end
int size = file.tellg(); // Get file size
cout << "File size: " << size << " bytes" << endl;
file.seekg(10); // Move to byte 10
char ch;
file.read(&ch, 1);
cout << "Byte at 10: " << ch << endl;
file.close();
return 0;
}
5. Error Handling in File Handling
File operations can fail (e.g., disk full, permission denied). Use:
fail(): Checks for errors (e.g., corrupt data).eof(): Checks end-of-file (not for errors!).bad(): Checks for unrecoverable errors (e.g., disk failure).
Example: Robust File Reading
#include <fstream>
#include <iostream>
using namespace std;
int main() {
ifstream fin("data.txt");
if (!fin.is_open()) {
cerr << "Error opening file!" << endl;
return 1;
}
string line;
while (getline(fin, line)) {
if (fin.fail()) {
cerr << "Error reading line!" << endl;
break;
}
cout << line << endl;
}
fin.close();
return 0;
}
6. File Handling in Real-World Applications
In the Real World
eSewa Transaction Logs
- Idea: eSewa stores every transaction (e.g., "User X paid Y NPR to User Z") in a text file with timestamps.
- How: Uses
ofstreamto append logs in real-time. - Example: When you pay a merchant, eSewa writes:
2024-05-20 12:34:56 | User123 | 500 | Merchant456 | Success
Daraz Order Processing
- Idea: Daraz saves order details (customer, items, status) in a binary file for faster retrieval.
- How: Uses
fstreamwithios::binaryto store structured data (e.g.,Orderobjects). - Worked Example:
Suppose Daraz receives 100 orders/day. A binary file stores each order as:
To check Alice’s order status, Daraz reads the binary file sequentially or uses[OrderID:1001, Customer:Alice, Items:[Laptop,Phone], Status:Shipped]seekg()to jump to her record.
NTC Call Records
- Idea: NTC logs call data (e.g., duration, time, numbers) in comma-separated text files for billing.
- How: Uses
ofstreamto append records daily. - Example File Snippet:
9841234567,9812345678,2024-05-20,10:30,120
7. Advantages and Disadvantages
| Advantages | Disadvantages |
|---|---|
| Persistent storage (survives program termination). | Slower than RAM access. |
| Large data storage (e.g., databases). | File corruption risk (e.g., power loss). |
| Shared across multiple programs. | Requires error handling (e.g., fail()). |
| Supports text/binary formats. | Manual management (e.g., closing files). |
8. Comparison: Text vs. Binary Files
| Feature | Text Files | Binary Files |
|---|---|---|
| Format | Human-readable (ASCII/Unicode). | Machine-readable (raw bytes). |
| Speed | Slower (conversions needed). | Faster (direct byte access). |
| Size | Larger (extra characters for formatting). | Smaller (no overhead). |
| Use Case | Logs, config files. | Databases, images, serialized objects. |
| Example | students.txt |
students.dat |
9. Worked Example: Copy File 1 to File 2
Problem: Write a program to copy the contents of source.txt to destination.txt.
Solution:
#include <fstream>
#include <iostream>
using namespace std;
int main() {
ifstream source("source.txt");
ofstream dest("destination.txt");
if (!source.is_open() || !dest.is_open()) {
cerr << "Error opening files!" << endl;
return 1;
}
char ch;
while (source.get(ch)) { // Read character-by-character
dest.put(ch); // Write to destination
}
source.close();
dest.close();
cout << "File copied successfully!" << endl;
return 0;
}
Trace:
| Step | Action | source State |
dest State |
|---|---|---|---|
| 1 | source.open("source.txt") |
Open, pointer at start | Open, empty |
| 2 | source.get(ch) |
ch = 'H' (first char) |
- |
| 3 | dest.put(ch) |
ch = 'e' |
Writes 'H' to file |
| ... | ... | ... | ... |
| 10 | source.eof() |
true (end reached) |
File fully copied |
10. Exam Tips
Understand Stream Classes:
- Know the difference between
ifstream,ofstream, andfstream. Always check if files are opened (is_open()).
- Know the difference between
Error Handling:
- Use
fail(),eof(), andbad()to handle errors gracefully. Example:if (fin.fail()) { cerr << "Read error!" << endl; }
- Use
Binary vs. Text:
- Text files are human-readable but slower; binary files are faster but require
ios::binarymode.
- Text files are human-readable but slower; binary files are faster but require
Random Access:
- Use
seekg()andseekp()for direct access (e.g., jumping to a record in a database).
- Use
Real-World Mapping:
- Link file handling to apps like eSewa logs, Daraz orders, or NTC call records. Explain how streams are used.
Code Structure:
- Always include
<fstream>and useusing namespace std;(or qualify withstd::). - Close files explicitly (
close()) for large files to free resources.
- Always include
Common Pitfalls:
- Forgetting to check
is_open()before operations. - Mixing text and binary modes without
ios::binary. - Not handling
fail()orbad()errors.
- Forgetting to check
Sample Exam Question:
Write a program to read a text file containing student names and ages, then write them to another file in reverse order (last student first).
Solution:
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
struct Student {
string name;
int age;
};
int main() {
ifstream fin("input.txt");
ofstream fout("output.txt");
vector<Student> students;
if (!fin.is_open() || !fout.is_open()) {
cerr << "Error opening files!" << endl;
return 1;
}
string line;
while (getline(fin, line)) {
size_t comma = line.find(',');
Student s;
s.name = line.substr(0, comma);
s.age = stoi(line.substr(comma + 1));
students.push_back(s);
}
reverse(students.begin(), students.end());
for (const auto& s : students) {
fout << s.name << "," << s.age << endl;
}
fin.close();
fout.close();
return 0;
}
Trace:
- Reads
Alice,20→Bob,21→Charlie,19intostudents. - Reverses the vector:
Charlie,19→Bob,21→Alice,20. - Writes to
output.txtin reverse order.
Based on the TU BIT syllabus for Object Oriented Programming (BIT153), unit 8.
Discussion
Loading…