C++ File Handling is a critical skill for managing persistent data, application logging, and complex data processing.
This comprehensive guide provides 25 practical C++ File Handling Exercises, designed to advance your skills from simple text I/O to advanced binary data files and custom structures.
Each exercise provides a clear problem statement, a helpful hint, a complete C++ solution, and a detailed explanation, ensuring you not only solve the problem but deeply understand why the solution works
+ Table Of Contents
Table of contents
- Exercise 1: Create and Write
- Exercise 2: Read and Display
- Exercise 3: Append to File
- Exercise 4: Count Characters
- Exercise 5: Count Lines
- Exercise 6: Copy File
- Exercise 7: Check File Existence
- Exercise 8: Clear File Content
- Exercise 9: Word Counter
- Exercise 10: Line Numbering
- Exercise 11: Simple Search
- Exercise 12: Case Conversion
- Exercise 13: Data Storage (Integers)
- Exercise 14: Data Retrieval (Average)
- Exercise 15: Filtering Lines
- Exercise 16: Log File Creator
- Exercise 17: Reverse File Content (Line by Line)
- Exercise 18: Structure I/O (Text)
- Exercise 19: Structure Retrieval (Text)
- Exercise 20: Binary Write (Integers)
- Exercise 21: Binary Read (Integers)
- Exercise 22: Update Record (Binary)
- Exercise 23: File Size
- Exercise 24: Random Access Read
- Exercise 25: Exception Handling
What You’ll Practice
The coding challenges covers the following core file handling topics:
- Basic I/O: Reading, writing, appending, and closing text files using
fstream,ifstream, andofstream. - Sequential Access & Parsing: Handling content line-by-line (
std::getline), and parsing delimited data usingstd::stringstream. - Text Processing: Counting elements, searching, filtering, and case conversion.
- Data Structures & Binary I/O: Reading and writing user-defined structures and raw bytes using Binary I/O (
read()andwrite()). - Advanced Control: Implementing Random Access with
seekg()/seekp()and robust Error Handling (is_open()).
Exercise 1: Create and Write
Problem Statement: Problem Statement Write a program to create a new text file named mydata.txt. Open the file for output and write the single line of text Hello, File Handling! into it. Ensure the program handles the closing of the file stream properly.
Expected Output:
Successfully wrote data to mydata.txt
mydata.txt File content:
Hello, File Handling!
+ Hint
- Use the
std::ofstreamclass, which is specialized for writing to files. - The file is created automatically if it does not exist when you declare the
ofstreamobject with the filename. - You can use the insertion operator
<<just like you do withstd::cout.
+ Show Solution
#include <fstream>
#include <iostream>
#include <string>
int main() {
// 1. Declare an output file stream object
std::ofstream outFile;
// 2. Open the file (creates it if it doesn't exist)
outFile.open("mydata.txt");
// 3. Check if the file was successfully opened
if (outFile.is_open()) {
// 4. Write data to the file
outFile << "Hello, File Handling!" << std::endl;
std::cout << "Successfully wrote data to mydata.txt" << std::endl;
// 5. Close the file stream
outFile.close();
} else {
std::cerr << "Unable to open file mydata.txt" << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- This exercise introduces the file writing:
std::ofstream. We declare an object,outFile, and call itsopen()method with the desired filename. - The crucial step is the error check using
is_open(); if this fails, the program reports an error. - The output is written using the standard stream insertion operator
<<. - Finally,
outFile.close()is called to flush any remaining buffer data and release the file handle back to the operating system.
Exercise 2: Read and Display
Problem Statement: Read the entire content from the existing file mydata.txt (created in Exercise 1) and display it line by line on the console. Report an error if the file cannot be opened.
Expected Output:
--- Content of mydata.txt ---
Hello, File Handling!
+ Hint
- Use the
std::ifstreamclass for reading. - A common way to read line by line is to use the
std::getline()function, which takes the file stream and astd::stringvariable as arguments, and reads until a newline character is encountered.
+ Show Solution
#include <fstream>
#include <iostream>
#include <string>
int main() {
// 1. Declare an input file stream object
std::ifstream inFile("mydata.txt");
std::string fileLine;
// 2. Check if the file was successfully opened
if (inFile.is_open()) {
std::cout << "--- Content of mydata.txt ---" << std::endl;
// 3. Read the file line by line
while (std::getline(inFile, fileLine)) {
// 4. Display the read line
std::cout << fileLine << std::endl;
}
// 5. Close the file stream
inFile.close();
} else {
// 6. Report error if file opening failed
std::cerr << "Error: Unable to open file mydata.txt for reading." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
The std::ifstream object, inFile, is used to read the data.
The core reading loop uses while (std::getline(inFile, fileLine)). The std::getline() function attempts to read an entire line into the fileLine string. This function returns a reference to the stream object, which evaluates to true if the read was successful and false (terminating the loop) if the end-of-file (EOF) is reached or an error occurs. This is the idiomatic way to process text files line by line in C++.
Exercise 3: Append to File
Problem Statement: Write a program to open the existing file mydata.txt and append the line This is the appended text. to the end of the file. The original content should remain intact.
Expected Output:
Successfully appended text to mydata.txt
mydata.txt content:
Hello, File Handling!
This is the appended text.
+ Hint
When opening the file using std::ofstream, you need to specify the append file mode using std::ios::app. This ensures that any new data written will be placed at the current end of the file.
+ Show Solution
#include <fstream>
#include <iostream>
int main() {
// 1. Declare an output file stream and open in append mode
std::ofstream outFile("mydata.txt", std::ios::app);
// 2. Check for successful opening
if (outFile.is_open()) {
// 3. Append the new line
outFile << "This is the appended text." << std::endl;
std::cout << "Successfully appended text to mydata.txt" << std::endl;
// 4. Close the file stream
outFile.close();
} else {
std::cerr << "Unable to open file mydata.txt for appending." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- The key change here is the use of the second argument in the
ofstreamconstructor:std::ios::app. This file mode flag modifies the behavior of the stream so that all output operations are performed at the end of the file, preserving the previous content. - If this flag were omitted, the default behavior would be to truncate (delete) the file content and start writing from the beginning.
Exercise 4: Count Characters
Problem Statement: Read the content of the file mydata.txt and count the total number of characters it contains. Display the final count on the console. Newline characters should also be counted.
Expected Output:
Total number of characters in mydata.txt: 49
+ Hint
- Read the file character by character using the
get()method of theifstreamobject. - The loop continues as long as the stream is successfully reading characters.
+ Show Solution
#include <fstream>
#include <iostream>
int main() {
std::ifstream inFile("mydata.txt");
char character;
int charCount = 0;
if (inFile.is_open()) {
// Read character by character until the end of the file
while (inFile.get(character)) {
charCount++;
}
std::cout << "Total number of characters in mydata.txt: " << charCount << std::endl;
inFile.close();
} else {
std::cerr << "Error: Unable to open file." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- This program uses a
whileloop withinFile.get(character). Theget()method attempts to extract a single character (including whitespace and newline characters) and store it in thecharactervariable. - If the extraction is successful, the stream object evaluates to
true, the loop continues, and thecharCountis incremented. When the end of the file is reached or an error occurs, the stream evaluates tofalse, and the loop terminates.
Exercise 5: Count Lines
Problem Statement: Read the content of the file mydata.txt and count the total number of lines present in the file. Display the final count on the console. An empty file should have a line count of 0.
Expected Output:
Total number of lines in mydata.txt: 2
+ Hint
- Use the
std::getline()function within a loop. - Since
getline()reads until a newline, every successful call to it represents one line counted.
+ Show Solution
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::ifstream inFile("mydata.txt");
std::string line;
int lineCount = 0;
if (inFile.is_open()) {
// Use getline() to read line by line
while (std::getline(inFile, line)) {
lineCount++;
}
std::cout << "Total number of lines in mydata.txt: " << lineCount << std::endl;
inFile.close();
} else {
std::cerr << "Error: Unable to open file." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- This solution leverages the behavior of
std::getline(). Each timestd::getline()successfully reads a sequence of characters up to a newline and stores it in thelinestring, thelineCountis incremented. - The loop naturally terminates when the end of the file is reached. This is the most efficient and standard way to count lines in a text file using C++ streams.
Exercise 6: Copy File
Problem Statement: Write a program that copies the content of a file named source.txt to a new file called destination.txt. Both files must be handled correctly, including opening and closing the streams.
Expected Output:
File copied successfully from mydata.txt to destination.txt
destination.txt content:
Hello, File Handling!
This is the appended text.
+ Hint
- You will need two file stream objects: an
std::ifstreamfor reading the source and anstd::ofstreamfor writing to the destination. - Use a
whileloop andstd::getline()to transfer data line by line.
+ Show Solution
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::ifstream sourceFile("mydata.txt");
std::ofstream destFile("destination.txt");
std::string line;
// Check if both files opened successfully
if (sourceFile.is_open() && destFile.is_open()) {
// Read from source line by line and write to destination
while (std::getline(sourceFile, line)) {
destFile << line << std::endl;
}
std::cout << "File copied successfully from mydata.txt to destination.txt" << std::endl;
sourceFile.close();
destFile.close();
} else if (!sourceFile.is_open()) {
std::cerr << "Error: Could not open mydata.txt." << std::endl;
} else {
std::cerr << "Error: Could not create/open destination.txt." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
This program demonstrates simultaneous input and output file handling.
- The condition
if (sourceFile.is_open() && destFile.is_open()), ensuring both operations are possible before proceeding. - The
whileloop reads a line from the source file usinggetline()and immediately writes that line to the destination file using the stream insertion operator<<. - Note that
std::endlis written explicitly to the destination file, asgetline()consumes the newline character from the input stream.
Exercise 7: Check File Existence
Problem Statement: Ask the user to enter a filename. Write a program to check if the specified file exists and can be opened for reading. Output a clear message indicating whether the file was found or not.
Expected Output:
Enter the filename to check: mydata.txt
SUCCESS: File 'mydata.txt' was found and opened successfully.
+ Hint
- Attempt to open the file using
std::ifstream. - If the file exists and the program has permission to read it, the stream object’s
is_open()method will return true.
+ Show Solution
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::string filename;
std::cout << "Enter the filename to check: ";
std::cin >> filename;
// Attempt to open the file for reading
std::ifstream testFile(filename);
// Check the state of the stream
if (testFile.is_open()) {
std::cout << "SUCCESS: File '" << filename << "' was found and opened successfully." << std::endl;
testFile.close(); // Close immediately as we only checked existence
} else {
std::cout << "FAILURE: File '" << filename << "' was not found or could not be opened." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- The program takes the filename from the user and attempts to construct an
std::ifstreamobject. - C++ file streams implicitly attempt to open the file during construction. By immediately calling
is_open()on thetestFileobject, we can reliably determine if the operating system successfully located and granted read access to the file. This is the simplest and most common method for checking file existence in C++.
Exercise 8: Clear File Content
Problem Statement: Write a program that effectively clears all content from an existing file named destination.txt without deleting the file itself.
Expected Output:
File 'destination.txt' content has been cleared (truncated).
Verification: File is now empty.
+ Hint
Opening an std::ofstream without specifying any special mode flags (like std::ios::app) automatically uses the default output mode, which includes the truncate flag (std::ios::trunc). This mode deletes the file’s previous content upon opening.
+ Show Solution
#include <fstream>
#include <iostream>
int main() {
// 1. The default mode for ofstream includes std::ios::trunc
std::ofstream clearFile("destination.txt");
if (clearFile.is_open()) {
// 2. Closing the file without writing anything clears the content
clearFile.close();
std::cout << "File 'destination.txt' content has been cleared (truncated)." << std::endl;
} else {
std::cerr << "Error: Could not open/clear file 'destination.txt'." << std::endl;
}
// Optional: Re-open in read mode to verify it's empty
std::ifstream checkFile("destination.txt");
if (checkFile.peek() == std::ifstream::traits_type::eof()) {
std::cout << "Verification: File is now empty." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- The core trick here lies in the default behavior of
std::ofstream. When you declare and openstd::ofstream clearFile("destination.txt"), the file is automatically opened with thestd::ios::outandstd::ios::truncflags. - The
std::ios::truncflag means “truncate the file to zero length upon opening.” By opening the file and immediately closing it without writing any data, we achieve the goal of clearing its content while keeping the file structure intact.
Exercise 9: Word Counter
Problem Statement: Read a file named mydata.txt and count the total number of words it contains. Assume that words are separated by any form of whitespace (spaces, newlines, tabs). Display the final word count.
Expected Output:
Total number of words in mydata.txt: 8
+ Hint
- The stream extraction operator
>>is designed to skip leading whitespace and read a single, non-whitespace sequence into astd::stringvariable. - Using this operator in a loop is the most idiomatic way to count words.
+ Show Solution
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::ifstream inFile("mydata.txt");
std::string word;
int wordCount = 0;
if (inFile.is_open()) {
// Loop uses the stream extraction operator (>>)
while (inFile >> word) {
wordCount++;
}
std::cout << "Total number of words in mydata.txt: " << wordCount << std::endl;
inFile.close();
} else {
std::cerr << "Error: Unable to open mydata.txt." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- Unlike
std::getline(), which reads up to a newline, the stream extraction operator>>automatically handles delimiting data by whitespace. - When used in a
whileloop with a file stream, it repeatedly attempts to extract the next word (non-whitespace sequence) into thewordvariable. - Each successful extraction increments
wordCount, providing an elegant and concise way to count words regardless of whether they are separated by spaces, tabs, or newlines.
Exercise 10: Line Numbering
Problem Statement: Read the content of mydata.txt line by line and write the content to a new file, numbered_output.txt. Each line in the output file must be prepended with its 1-based line number, followed by a colon and a space (e.g., “1: First line of text”).
Expected Output:
Successfully numbered lines into numbered_output.txt
numbered_output.txt content:
1: Hello, File Handling!
2: This is the appended text.
+ Hint
- You will need two stream objects (
ifstreamandofstream) and an integer variable initialized to 1 to track the line number. - Use
std::getline()to read the input file.
+ Show Solution
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::ifstream inFile("mydata.txt");
std::ofstream outFile("numbered_output.txt");
std::string line;
int lineNumber = 1;
if (inFile.is_open() && outFile.is_open()) {
while (std::getline(inFile, line)) {
// Write line number, colon, and the line content to the output file
outFile << lineNumber << ": " << line << std::endl;
lineNumber++;
}
std::cout << "Successfully numbered lines into numbered_output.txt" << std::endl;
inFile.close();
outFile.close();
} else {
std::cerr << "Error: Failed to open one or both files." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- This exercise reinforces the use of
std::getline()for sequential line processing. - Inside the
whileloop, the current line number is written to the output stream first, followed by the delimiter “: “ and the actual content stored in thelinestring. The use ofstd::endlensures that each numbered entry occupies its own line in the output file. - The
lineNumbervariable is incremented at the end of each iteration.
Exercise 11: Simple Search
Problem Statement: Ask the user for a word (a search key). Read a file named mydata.txt and determine if the search key exists anywhere within the file. Report the result (found or not found) to the user.
Expected Output:
Enter the word to search for: Hello
SUCCESS: The word 'Hello' was found in the document.
+ Hint
Read the file line by line using std::getline(). For each line, use the std::string::find() method, which returns std::string::npos if the substring is not found.
+ Show Solution
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::ifstream inFile("mydata.txt");
std::string searchKey;
std::string line;
bool found = false;
std::cout << "Enter the word to search for: ";
std::cin >> searchKey;
if (inFile.is_open()) {
while (std::getline(inFile, line)) {
// Check if the searchKey exists within the current line
if (line.find(searchKey) != std::string::npos) {
found = true;
break; // Stop searching once found
}
}
inFile.close();
if (found) {
std::cout << "SUCCESS: The word '" << searchKey << "' was found in the document." << std::endl;
} else {
std::cout << "NOT FOUND: The word '" << searchKey << "' was not present." << std::endl;
}
} else {
std::cerr << "Error: Unable to open mydata.txt." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- This solution combines file reading with string manipulation. The
std::string::find(searchKey)method performs the core logic. If the substring is found,find()returns the starting position (an index), which is never equal tostd::string::npos(a constant representing “not a position”). - Once the word is found, the
foundflag is set totrue, andbreakimmediately exits the loop, optimizing performance by not reading the rest of the file.
Exercise 12: Case Conversion
Problem Statement: Read the content of a file named mydata.txt and write all its content to a new output file, uppercase.txt, converting every letter to uppercase. Non-alphabetic characters should remain unchanged.
Expected Output:
Content successfully converted to uppercase and saved to uppercase.txt
uppercase.txt Content:
HELLO, FILE HANDLING!
THIS IS THE APPENDED TEXT.
+ Hint
- Read the file character by character using
get(). - Use the
std::toupper()function (from the<cctype>header) on each character before writing it to the output file.
+ Show Solution
#include <fstream>
#include <iostream>
#include <cctype> // Required for std::toupper
int main() {
std::ifstream inFile("mydata.txt");
std::ofstream outFile("uppercase.txt");
char character;
if (inFile.is_open() && outFile.is_open()) {
// Read character by character
while (inFile.get(character)) {
// Convert character to uppercase and write to the output file
outFile.put(static_cast<char>(std::toupper(character)));
}
std::cout << "Content successfully converted to uppercase and saved to uppercase.txt" << std::endl;
inFile.close();
outFile.close();
} else {
std::cerr << "Error: Failed to open one or both files." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- This program uses a character-by-character approach for detailed manipulation.
inFile.get(character)reads every byte. - The core transformation is done by
std::toupper(character), which converts the character to uppercase if it’s a lowercase letter, and returns the character unchanged otherwise. outFile.put()is used to write a single character back to the file. Thestatic_cast<char>is necessary becausestd::toupper()returns anint(representing the character’s ASCII/Unicode value).
Exercise 13: Data Storage (Integers)
Problem Statement: Ask the user to enter five integer values. Write these five numbers, each on a separate line, into a file named numbers.txt.
Expected Output:
Enter five integers (press Enter after each):
Integer 1: 10
Integer 2: 20
Integer 3: 30
Integer 4: 40
Integer 5: 50
Five integers successfully written to numbers.txt.
+ Hint
- Use a
forloop to iterate five times, prompting the user for input usingstd::cininside the loop. - Use
std::ofstreamand the insertion operator<<to write the number followed bystd::endl.
+ Show Solution
#include <fstream>
#include <iostream>
int main() {
std::ofstream outFile("numbers.txt");
int number;
if (outFile.is_open()) {
std::cout << "Enter five integers (press Enter after each):" << std::endl;
for (int i = 0; i < 5; ++i) {
std::cout << "Integer " << (i + 1) << ": ";
std::cin >> number;
// Write the number followed by a newline
outFile << number << std::endl;
}
outFile.close();
std::cout << "Five integers successfully written to numbers.txt." << std::endl;
} else {
std::cerr << "Error: Could not open numbers.txt for writing." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- This exercise is a straightforward application of
std::ofstreamcombined with basic user input. - The
forloop controls the number of inputs taken. - Inside the loop, the input is read into the
numbervariable usingstd::cin, and then written to the file usingoutFile << number << std::endl. Usingstd::endlensures that each integer is stored on its own line.
Exercise 14: Data Retrieval (Average)
Problem Statement: Read the integers stored in numbers.txt (created in Exercise 13). Calculate the sum and the average of all the numbers in the file. Display both the sum and the average.
Expected Output:
Total numbers read: 5
Sum of numbers: 150
Average of numbers: 30.00
+ Hint
- Use a
std::ifstreamobject and the extraction operator>>within awhileloop to read integers. - Keep track of the total sum and the count of numbers read to calculate the average.
+ Show Solution
#include <fstream>
#include <iostream>
#include <iomanip> // For std::fixed and std::setprecision
int main() {
std::ifstream inFile("numbers.txt");
int number;
double sum = 0.0;
int count = 0;
if (inFile.is_open()) {
// Read number by number until EOF
while (inFile >> number) {
sum += number;
count++;
}
inFile.close();
if (count > 0) {
double average = sum / count;
std::cout << "Total numbers read: " << count << std::endl;
std::cout << "Sum of numbers: " << sum << std::endl;
// Display average with two decimal places
std::cout << std::fixed << std::setprecision(2);
std::cout << "Average of numbers: " << average << std::endl;
} else {
std::cout << "The file numbers.txt is empty." << std::endl;
}
} else {
std::cerr << "Error: Could not open numbers.txt for reading." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- This solution uses the powerful feature of the stream extraction operator
>>to read structured data. When reading from a file of numbers, the loopwhile (inFile >> number)handles parsing the text data into the integernumberand automatically stops when the end of the file is reached or invalid data is encountered. - We track the
sumandcountto calculate theaverage, ensuring we check ifcountis greater than zero to avoid division by zero.
Exercise 15: Filtering Lines
Problem Statement: Read a file named log_data.txt. Write only the lines that start with the letter ‘H’ (case-insensitive) to a new file called filtered_log.txt.
Given:
log_data.txt Content:
Hello, File Handling!
This is the appended text.
hello, cpp File Handling!
Expected Output:
filtered_log.txt Content:
Hello, File Handling!
hello, cpp File Handling!
+ Hint
- Read line by line using
std::getline(). - For each line, check if the line is not empty and if its first character, after converting it to uppercase using
std::toupper(), is equal to ‘H’.
+ Show Solution
#include <fstream>
#include <iostream>
#include <string>
#include <cctype>
int main() {
std::ifstream inFile("mydata.txt");
std::ofstream outFile("filtered_log.txt");
std::string line;
if (inFile.is_open() && outFile.is_open()) {
while (std::getline(inFile, line)) {
// Check if the line is not empty AND starts with 'E' or 'e'
if (!line.empty() && std::toupper(line[0]) == 'H') {
outFile << line << std::endl;
}
}
std::cout << "Filtering complete. Matching lines saved to filtered_log.txt" << std::endl;
inFile.close();
outFile.close();
} else {
std::cerr << "Error: Failed to open one or both files." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- This exercise demonstrates conditional writing based on line content.
- The check
!line.empty()prevents an error if an empty line is encountered. - The core filtering logic is
std::toupper(line[0]) == 'H'. By converting the first characterline[0]to uppercase before comparison, the check becomes case-insensitive, matching lines that start with either ‘H’ or ‘h’. Only if the condition is true is the line written to the output file.
Exercise 16: Log File Creator
Problem Statement: Write a function named write_log(const std::string& message) that takes a string message and appends it to a file named system.log. The function must prepend the message with the current time and date in a simple format before writing it to the file.
Expected Output:
Log entries written to system.log
system.log Content:
[2025-11-01 06:54:41] Application started successfully.
[2025-11-01 06:54:41] User accessed database.
[2025-11-01 06:54:41] Error: Invalid login attempt detected.
+ Hint
- Use the
<ctime>header to get the current time. Specifically, usestd::time(),std::localtime(), andstd::put_time()(orstd::strftime()for older compilers) to format the timestamp string. - Remember to open the file in append mode (
std::ios::app).
+ Show Solution
#include <fstream>
#include <iostream>
#include <string>
#include <chrono> // For modern time handling
#include <ctime> // For std::time_t, std::localtime
#include <iomanip> // For std::put_time
void write_log(const std::string& message) {
// Open file in append mode
std::ofstream logFile("system.log", std::ios::app);
if (logFile.is_open()) {
// Get current time
auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
// Convert time to local structure
// Note: localtime is generally thread-unsafe, use localtime_s/localtime_r in production
std::tm* localTime = std::localtime(&now);
// Write the formatted timestamp
logFile << "[" << std::put_time(localTime, "%Y-%m-%d %H:%M:%S") << "] ";
// Write the user message and a newline
logFile << message << std::endl;
logFile.close();
} else {
// Output error to console if logging fails
std::cerr << "CRITICAL: Log file writing failed!" << std::endl;
}
}
int main() {
write_log("Application started successfully.");
write_log("User accessed database.");
write_log("Error: Invalid login attempt detected.");
std::cout << "Log entries written to system.log" << std::endl;
return 0;
}Code language: C++ (cpp)
Explanation:
This solution introduces basic date/time formatting for robust logging
- The file is opened with
std::ios::appto ensure new messages are always added to the end. - Time handling involves converting the current system time to a
std::tmstructure usingstd::localtime.std::put_time()is then used with the format string"%Y-%m-%d %H:%M:%S"to neatly format the timestamp directly into the output stream. The function successfully encapsulates the logging logic, making it reusable.
Exercise 17: Reverse File Content (Line by Line)
Problem Statement: Read all lines of a file named mydata.txt into an in-memory structure. Reverse the order of these lines and write them to a new file called reversed.txt. The last line of the original file should be the first line of the new file, and so on.
This exercise demonstrates intermediate data storage before output.
Expected Output:
Lines reversed and saved to reversed.txt
reversed.txt Content
hello, cpp File Handling!
This is the appended text.
Hello, File Handling!
+ Hint
- Store the lines in a
std::vector<std::string>. - Once all lines are read, iterate over the vector in reverse order (from the last element to the first) and write each string to the output file.
+ Show Solution
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm> // Not strictly necessary but useful for reverse()
int main() {
std::ifstream inFile("mydata.txt");
std::ofstream outFile("reversed.txt");
std::string line;
std::vector<std::string> lines;
if (inFile.is_open() && outFile.is_open()) {
// 1. Read all lines into the vector
while (std::getline(inFile, line)) {
lines.push_back(line);
}
inFile.close();
// 2. Write lines to the output file in reverse order
for (auto it = lines.rbegin(); it != lines.rend(); ++it) {
outFile << *it << std::endl;
}
outFile.close();
std::cout << "Lines reversed and saved to reversed.txt" << std::endl;
} else {
std::cerr << "Error: Failed to open files." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- All content is first loaded into the
linesvector. - The reversal logic uses reverse iterators:
lines.rbegin()points to the last element of the vector, andlines.rend()points one past the first element. - Iterating from
rbegin()torend()effectively processes the vector from back to front, achieving the line reversal.
Exercise 18: Structure I/O (Text)
Problem Statement: Define a C++ structure named Person with private members: std::string name and int age. Implement a program that prompts the user for data for three people and writes their name and age, separated by a comma on the same line, into a text file named people_text.txt.
Expected Output:
Enter data for 3 people:
Person 1 Name: Jessa
Person 1 Age: 28
Person 2 Name: Jon
Person 2 Age: 35
Person 3 Name: Kerry
Person 3 Age: 30
Data successfully written to people_text.txt.
+ Hint
- Use a
structorclassto definePerson. - Use a
forloop to collect data for three instances. - Write the data using
std::ofstreamand ensure a delimiter (like a comma) separates the fields so they can be parsed later.
+ Show Solution
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
struct Person {
std::string name;
int age;
};
int main() {
std::ofstream outFile("people_text.txt");
std::vector<Person> people(3);
if (outFile.is_open()) {
std::cout << "Enter data for 3 people:" << std::endl;
for (int i = 0; i < 3; ++i) {
std::cout << "Person " << (i + 1) << " Name: ";
std::cin.ignore(); // Consume any leftover newline
std::getline(std::cin, people[i].name);
std::cout << "Person " << (i + 1) << " Age: ";
std::cin >> people[i].age;
// Write structured data as Name,Age
outFile << people[i].name << "," << people[i].age << std::endl;
}
outFile.close();
std::cout << "\nData successfully written to people_text.txt." << std::endl;
} else {
std::cerr << "Error: Could not open people_text.txt for writing." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- The
Personstructure is defined to hold the related data. - We use
std::getline(std::cin, ...)for the name to capture full names with spaces andstd::cin >> ...for the age. - The data is written to the file using a comma as a separator, converting the structured data into a flat, readable text format. This design ensures the data can be correctly reconstructed (parsed).
Exercise 19: Structure Retrieval (Text)
Problem Statement: Read the structured, comma-separated data from people_text.txt (created in Exercise 18). Parse each line and reconstruct the data into a std::vector<Person>. Finally, display all the retrieved records on the console.
Expected Output:
--- Retrieved People Data ---
Name: Jessa, Age: 28
Name: Jon, Age: 35
Name: Kerry, Age: 30
+ Hint
- Read the file line by line using
std::getline(). For each line, usestd::stringstreamandstd::getline(ss, field, ',')to separate the name and age. - Remember to convert the age string back into an integer using
std::stoi().
+ Show Solution
#include <fstream>
#include <sstream>
#include <iostream>
#include <string>
#include <vector>
struct Person {
std::string name;
int age;
};
int main() {
std::ifstream inFile("people_text.txt");
std::vector<Person> retrievedPeople;
std::string line, nameStr, ageStr;
if (inFile.is_open()) {
while (std::getline(inFile, line)) {
std::stringstream ss(line);
// Extract Name (field 1)
std::getline(ss, nameStr, ',');
// Extract Age (field 2)
std::getline(ss, ageStr, ',');
Person p;
p.name = nameStr;
try {
p.age = std::stoi(ageStr); // Convert string to integer
retrievedPeople.push_back(p);
} catch (const std::exception& e) {
std::cerr << "Skipping malformed record: " << e.what() << std::endl;
}
}
inFile.close();
std::cout << "\n--- Retrieved People Data ---" << std::endl;
for (const auto& p : retrievedPeople) {
std::cout << "Name: " << p.name << ", Age: " << p.age << std::endl;
}
} else {
std::cerr << "Error: Could not open people_text.txt for reading." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- This solution is the inverse of the previous one.
- It uses
std::stringstreamto break apart the comma-separated text into individual strings (nameStrandageStr). - Since the age was stored as text, it must be converted back to its original type (
int) usingstd::stoi()before being stored in thePersonstructure and added to the vector.
Exercise 20: Binary Write (Integers)
Problem Statement: Create an array of 5 integers. Write these 5 integers into a file named integers.bin in binary format. This means writing the raw memory representation of the integers, not their text form.
Expected Output:
Successfully wrote 5 integers in binary format to integers.bin
+ Hint
- Use
std::ofstreamopened with thestd::ios::binaryflag. - The stream’s
write()method is used for binary output. It requires a pointer to the start of the data buffer (cast toconst char*) and the size of the data in bytes (sizeof(data)).
+ Show Solution
#include <fstream>
#include <iostream>
int main() {
int data[] = {10, 255, 3000, 42, 99999};
int count = sizeof(data) / sizeof(data[0]);
// Open file in output and binary mode
std::ofstream outFile("integers.bin", std::ios::out | std::ios::binary);
if (outFile.is_open()) {
// Write the entire array's raw memory content
outFile.write(
reinterpret_cast<const char*>(data), // Pointer to data, cast to const char*
sizeof(data) // Total size of data in bytes
);
outFile.close();
std::cout << "Successfully wrote " << count << " integers in binary format to integers.bin." << std::endl;
} else {
std::cerr << "Error: Could not open integers.bin for binary writing." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- Binary file handling uses the
| std::ios::binaryflag. TheoutFile.write()method bypasses text formatting and writes the raw bytes directly from the memory location of thedataarray. - We use
reinterpret_cast<const char*>()to safely convert the pointer type, a necessary step for C++ streams. The total number of bytes written issizeof(data), which is5 * sizeof(int).
Exercise 21: Binary Read (Integers)
Problem Statement: Read the 5 integers back from the binary file integers.bin (created in Exercise 23). Store them in a new integer array or vector and display them on the console to verify the data integrity.
Expected Output:
Successfully read 5 integers from integers.bin:
Data[0]: 10
Data[1]: 255
Data[2]: 3000
Data[3]: 42
Data[4]: 99999
+ Hint
- Use
std::ifstreamopened with thestd::ios::binaryflag. - The stream’s
read()method is used for binary input. It requires a pointer to the destination buffer (cast tochar*) and the size of the data to read.
+ Show Solution
#include <fstream>
#include <iostream>
#include <vector>
int main() {
std::vector<int> readData(5); // Prepare space for 5 integers
size_t dataSize = readData.size() * sizeof(int);
// Open file in input and binary mode
std::ifstream inFile("integers.bin", std::ios::in | std::ios::binary);
if (inFile.is_open()) {
// Read the exact number of bytes into the vector's internal array
inFile.read(
reinterpret_cast<char*>(readData.data()), // Pointer to destination buffer
dataSize // Total size of data to read
);
inFile.close();
// Check if the read operation was successful (read all bytes)
if (inFile.gcount() == dataSize) {
std::cout << "Successfully read " << readData.size() << " integers from integers.bin:" << std::endl;
for (size_t i = 0; i < readData.size(); ++i) {
std::cout << "Data[" << i << "]: " << readData[i] << std::endl;
}
} else {
std::cerr << "Error: Did not read expected number of bytes. File may be corrupted/incomplete." << std::endl;
}
} else {
std::cerr << "Error: Could not open integers.bin for binary reading." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- This solution uses
inFile.read()to retrieve the raw bytes. - The data is read directly into the memory allocated for the
readDatavector usingreadData.data()(which returns a pointer to the vector’s underlying array). - The
gcount()method is essential in binary I/O; it returns the number of characters (bytes) successfully read by the last unformatted input operation, allowing us to verify the entire expected block of data was retrieved.
Exercise 22: Update Record (Binary)
Problem Statement: Define a structure Product containing int id and float price. Create a binary file products.bin with three initial product records. Then, write a program segment that uses seekp() and seekg() to find the second record (ID 2) and update its price in place without rewriting the entire file.
Expected Output:
Successfully updated price for record 2 to $75.25
+ Hint
- The file stream must be opened in update mode (
std::ios::in | std::ios::out | std::ios::binary). - The starting position of the second record is calculated as
1 * sizeof(Product). Useseekp()to move the put pointer (for writing) to the correct location.
+ Show Solution
#include <fstream>
#include <iostream>
struct Product {
int id;
float price;
};
int main() {
// 1. Setup and initial write (for testing)
Product products[] = {{1, 10.50f}, {2, 50.00f}, {3, 22.99f}};
std::fstream file("products.bin", std::ios::out | std::ios::binary | std::ios::trunc);
file.write(reinterpret_cast<const char*>(products), sizeof(products));
file.close();
// 2. Update operation
float newPrice = 75.25f;
int recordIndex = 1; // Index 1 for the second record (ID 2)
size_t offset = recordIndex * sizeof(Product); // Byte offset to the start of record 2
// Open file for reading AND writing (in/out) and binary mode
file.open("products.bin", std::ios::in | std::ios::out | std::ios::binary);
if (file.is_open()) {
// Calculate offset to the price member (within the struct)
// Offset = (Start of Record 2) + (Offset of 'price' member)
size_t priceOffset = offset + sizeof(int); // 'price' starts after 'id' (4 bytes)
// Move the write pointer (put pointer) to the start of the price field
file.seekp(priceOffset, std::ios::beg);
// Write the new price over the old one
file.write(reinterpret_cast<const char*>(&newPrice), sizeof(newPrice));
file.close();
std::cout << "Successfully updated price for record 2 to $" << newPrice << std::endl;
} else {
std::cerr << "Error: Could not open products.bin for update." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- This advanced exercise uses the
std::fstreamclass for simultaneous reading and writing. The file is opened withstd::ios::in | std::ios::outfor update access. - The key is calculating the exact byte offset to the data to be modified. Since the
pricemember is located after theidmember (which takessizeof(int)bytes), we move the put pointer (seekp()) to the start of the second record and then addsizeof(int)to land exactly on thepricefield. The new float value is then written, overwriting the old value.
Exercise 23: File Size
Problem Statement: Write a program that determines and outputs the size of a file named mydata.txt in bytes.
Expected Output:
The size of 'mydata.txt' is 63 bytes.
+ Hint
- Use
std::ifstreamopened in binary mode. - To find the size, use the stream’s
seekg()method to move the get pointer to the end of the file (std::ios::end), and then usetellg()to report the current position, which is the total file size in bytes
+ Show Solution
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::string filename = "mydata.txt";
// Create a dummy file for testing if it doesn't exist
std::ofstream temp(filename);
temp << "A relatively long string of content to give the file some size.";
temp.close();
// Open the file in binary mode for accurate size calculation
std::ifstream inFile(filename, std::ios::in | std::ios::binary);
long fileSize = 0;
if (inFile.is_open()) {
// 1. Move the get pointer to the end of the file
inFile.seekg(0, std::ios::end);
// 2. Get the position of the pointer (which is the file size)
fileSize = inFile.tellg();
inFile.close();
if (fileSize != -1) {
std::cout << "The size of '" << filename << "' is " << fileSize << " bytes." << std::endl;
} else {
std::cerr << "Error: Could not determine file size." << std::endl;
}
} else {
std::cerr << "Error: Could not open file " << filename << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- This technique is the standard way to determine file size in C++.
- By opening the file and moving the get pointer to the end using
inFile.seekg(0, std::ios::end)(offset 0 from the end), the pointer’s current location, retrieved byinFile.tellg(), corresponds exactly to the total number of bytes in the file. - The binary mode is used to prevent stream translators from altering the byte count due to character encoding.
Exercise 24: Random Access Read
Problem Statement: Read a text file named people_text.txt and display only the content that starts from the 8th character (index 8) up to the 20th character.
Expected Output:
--- Content from byte 8 to 20 ---
Jon,35
Kerry
+ Hint
- Use
std::ifstream. - Use
seekg()to directly position the get pointer to the desired starting byte offset (10). - Then, read the next 11 characters using a loop or an array read.
+ Show Solution
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
int main() {
// Note: Ensure long_document.txt exists and is large enough (>= 100 bytes)
std::ifstream inFile("people_text.txt", std::ios::binary); // Use binary for byte accuracy
int startOffset = 8; // 50th character (0-based index)
int bytesToRead = 12; // Read up to 20th character (8+12 = 20)
if (inFile.is_open()) {
// 1. Move the get pointer to the start offset
inFile.seekg(startOffset, std::ios::beg);
if (!inFile.fail()) {
// 2. Prepare a buffer to read the chunk
std::vector<char> buffer(bytesToRead + 1, '\0'); // +1 for null terminator
// 3. Read the specified number of bytes
inFile.read(buffer.data(), bytesToRead);
std::cout << "--- Content from byte " << startOffset << " to "
<< startOffset + inFile.gcount() << " ---" << std::endl;
// Output the read buffer (using gcount() for actual bytes read)
std::cout.write(buffer.data(), inFile.gcount());
std::cout << "\n----------------------------------------------------" << std::endl;
} else {
std::cerr << "Error: Failed to seek to position " << startOffset << std::endl;
}
inFile.close();
} else {
std::cerr << "Error: Could not open mydata.txt." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- This is an example of random access I/O. Instead of reading sequentially, we use
inFile.seekg(startOffset, std::ios::beg)to jump directly to byte 8 from the beginning (std::ios::beg). We then use the unformattedinFile.read()to extract the next 12 bytes directly into our buffer. - The
std::cout.write()method is used to print the content of the buffer, utilizinginFile.gcount()to ensure only the bytes successfully read (in case EOF was hit early) are displayed.
Exercise 25: Exception Handling
Problem Statement: Modify a file reading program (like Exercise 2) to use C++ exception handling. Configure the stream to throw exceptions on failure, and wrap the file operations in a try-catch block to gracefully catch and report std::ios_base::failure if the file cannot be opened.
Expected Output:
--- FILE I/O EXCEPTION CAUGHT ---
File: nonexistent.txt
Reason: basic_ios::clear: iostream error
Code: Check if file exists or if permissions are correct.
+ Hint
- Before attempting the file operation, use the stream’s
exceptions()method to set the stream state flags (std::ios::failbit | std::ios::badbit) that should trigger an exception. - This forces the stream to throw instead of just setting an internal error flag.
+ Show Solution
#include <fstream>
#include <iostream>
#include <string>
#include <stdexcept>
int main() {
std::string filename = "nonexistent.txt"; // A file guaranteed to fail opening
try {
std::ifstream inFile;
// 1. Tell the stream to throw exceptions on failure/bad states
inFile.exceptions(std::ios::failbit | std::ios::badbit);
// 2. Attempt to open the file (may throw here)
inFile.open(filename);
// If open succeeded (unlikely for nonexistent.txt):
std::string line;
while (std::getline(inFile, line)) {
std::cout << line << std::endl;
}
inFile.close();
} catch (const std::ios_base::failure& e) {
// 3. Catch the specific file stream exception
std::cerr << "--- FILE I/O EXCEPTION CAUGHT ---" << std::endl;
std::cerr << "File: " << filename << std::endl;
std::cerr << "Reason: " << e.what() << std::endl;
std::cerr << "Code: Check if file exists or if permissions are correct." << std::endl;
return 1;
} catch (const std::exception& e) {
// Catch any other standard exceptions
std::cerr << "Generic Error: " << e.what() << std::endl;
return 1;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- Standard C++ streams do not throw exceptions by default; they rely on checking internal state flags (
fail(),bad()). - This exercise forces exception behavior by calling
inFile.exceptions(std::ios::failbit | std::ios::badbit). - If the
inFile.open(filename)call fails (because the file doesn’t exist), the stream immediately throws an object of typestd::ios_base::failure. Thetry-catchblock cleanly intercepts this error, allowing the program to report the failure without crashing.

Leave a Reply