Coming Soon
This lesson is currently being developed
Basic file I/O
Read from and write to files.
What to Expect
Comprehensive explanations with practical examples
Interactive coding exercises to practice concepts
Knowledge quiz to test your understanding
Step-by-step guidance for beginners
Development Status
Content is being carefully crafted to provide the best learning experience
Preview
Early Preview Content
This content is still being developed and may change before publication.
28.6 — Basic file I/O
In this lesson, you'll learn how to read from and write to files using C++'s file stream classes, allowing your programs to persist data beyond program execution.
Why use file I/O?
File I/O (Input/Output) allows your programs to:
- Save data permanently (persist between program runs)
- Process large amounts of data stored in files
- Generate reports and logs
- Exchange data with other programs
- Create configuration files
Think of file I/O like reading a book or writing in a journal - the information is stored permanently and can be accessed later.
File stream classes
C++ provides specialized stream classes for file operations in the <fstream>
header:
std::ifstream
- Input file stream (reading from files)std::ofstream
- Output file stream (writing to files)std::fstream
- Input/output file stream (both reading and writing)
#include <fstream> // Required for file I/O
#include <iostream>
Writing to files with std::ofstream
Basic file writing
#include <fstream>
#include <iostream>
int main()
{
// Create an output file stream
std::ofstream outFile("example.txt");
// Check if file opened successfully
if (!outFile)
{
std::cerr << "Error: Could not create file!" << std::endl;
return 1;
}
// Write to the file (just like std::cout)
outFile << "Hello, File!" << std::endl;
outFile << "This is line 2." << std::endl;
outFile << "Numbers: " << 42 << ", " << 3.14 << std::endl;
// File automatically closes when outFile goes out of scope
return 0;
}
This creates a file named example.txt
with the following content:
Hello, File!
This is line 2.
Numbers: 42, 3.14
Writing different data types
#include <fstream>
#include <iostream>
#include <string>
int main()
{
std::ofstream outFile("data.txt");
if (!outFile.is_open())
{
std::cerr << "Error opening file for writing!" << std::endl;
return 1;
}
// Write various data types
std::string name = "Alice Johnson";
int age = 28;
double salary = 55000.50;
bool isEmployed = true;
outFile << "Employee Information:" << std::endl;
outFile << "Name: " << name << std::endl;
outFile << "Age: " << age << std::endl;
outFile << "Salary: $" << salary << std::endl;
outFile << "Employed: " << (isEmployed ? "Yes" : "No") << std::endl;
outFile.close(); // Explicitly close the file
std::cout << "Data written to data.txt successfully!" << std::endl;
return 0;
}
Output (in data.txt):
Employee Information:
Name: Alice Johnson
Age: 28
Salary: $55000.5
Employed: Yes
Reading from files with std::ifstream
Basic file reading
#include <fstream>
#include <iostream>
#include <string>
int main()
{
// Create an input file stream
std::ifstream inFile("example.txt");
// Check if file opened successfully
if (!inFile)
{
std::cerr << "Error: Could not open file for reading!" << std::endl;
return 1;
}
std::string line;
// Read file line by line
while (std::getline(inFile, line))
{
std::cout << line << std::endl;
}
return 0;
}
Output:
Hello, File!
This is line 2.
Numbers: 42, 3.14
Reading specific data types
#include <fstream>
#include <iostream>
#include <string>
int main()
{
std::ifstream inFile("numbers.txt");
if (!inFile.is_open())
{
std::cerr << "Error opening file!" << std::endl;
return 1;
}
int number;
double sum = 0.0;
int count = 0;
// Read numbers from file
while (inFile >> number)
{
std::cout << "Read number: " << number << std::endl;
sum += number;
count++;
}
if (count > 0)
{
std::cout << "Average: " << sum / count << std::endl;
}
return 0;
}
File opening modes
You can specify how to open a file using mode flags:
#include <fstream>
#include <iostream>
int main()
{
// Different opening modes
std::ofstream outFile1("file1.txt", std::ios::out); // Output mode (default for ofstream)
std::ofstream outFile2("file2.txt", std::ios::app); // Append mode
std::ofstream outFile3("file3.txt", std::ios::out | std::ios::trunc); // Truncate existing file
// Check if files opened successfully
if (!outFile2.is_open())
{
std::cerr << "Could not open file2.txt for appending!" << std::endl;
return 1;
}
// Writing to append mode - adds to end of existing file
outFile2 << "This line is appended to the file." << std::endl;
return 0;
}
Common file modes
std::ios::in
- Open for readingstd::ios::out
- Open for writingstd::ios::app
- Append to end of filestd::ios::trunc
- Truncate file if it existsstd::ios::binary
- Open in binary mode
Reading and writing structured data
Writing structured data
#include <fstream>
#include <iostream>
struct Student
{
std::string name;
int id;
double gpa;
};
int main()
{
std::ofstream outFile("students.txt");
if (!outFile.is_open())
{
std::cerr << "Error creating students file!" << std::endl;
return 1;
}
Student students[] = {
{"Alice Smith", 12345, 3.75},
{"Bob Johnson", 12346, 3.20},
{"Carol Brown", 12347, 3.95}
};
// Write header
outFile << "Name,ID,GPA" << std::endl;
// Write student data
for (const auto& student : students)
{
outFile << student.name << "," << student.id << "," << student.gpa << std::endl;
}
std::cout << "Student data written successfully!" << std::endl;
return 0;
}
Reading structured data
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
struct Student
{
std::string name;
int id;
double gpa;
};
int main()
{
std::ifstream inFile("students.txt");
if (!inFile.is_open())
{
std::cerr << "Error opening students file!" << std::endl;
return 1;
}
std::string line;
// Skip header line
std::getline(inFile, line);
// Read and parse each line
while (std::getline(inFile, line))
{
std::stringstream ss(line);
std::string item;
Student student;
// Parse comma-separated values
if (std::getline(ss, student.name, ',') &&
std::getline(ss, item, ',') &&
std::getline(ss, item))
{
student.id = std::stoi(ss.str().substr(student.name.length() + 1,
ss.str().find_last_of(',') - student.name.length() - 1));
student.gpa = std::stod(item);
std::cout << "Name: " << student.name
<< ", ID: " << student.id
<< ", GPA: " << student.gpa << std::endl;
}
}
return 0;
}
Error handling with file I/O
Comprehensive error checking
#include <fstream>
#include <iostream>
#include <string>
bool writeToFile(const std::string& filename, const std::string& data)
{
std::ofstream outFile(filename);
if (!outFile.is_open())
{
std::cerr << "Error: Unable to open " << filename << " for writing." << std::endl;
return false;
}
outFile << data;
if (outFile.fail())
{
std::cerr << "Error: Failed to write data to " << filename << std::endl;
return false;
}
return true;
}
bool readFromFile(const std::string& filename)
{
std::ifstream inFile(filename);
if (!inFile.is_open())
{
std::cerr << "Error: Unable to open " << filename << " for reading." << std::endl;
return false;
}
std::string line;
while (std::getline(inFile, line))
{
std::cout << line << std::endl;
}
if (inFile.bad())
{
std::cerr << "Error: An error occurred while reading from " << filename << std::endl;
return false;
}
return true;
}
int main()
{
const std::string filename = "test.txt";
const std::string data = "Hello, World!\nThis is a test file.\n";
// Write to file
if (writeToFile(filename, data))
{
std::cout << "Successfully wrote to " << filename << std::endl;
}
// Read from file
std::cout << "\nFile contents:" << std::endl;
if (!readFromFile(filename))
{
return 1;
}
return 0;
}
Output:
Successfully wrote to test.txt
File contents:
Hello, World!
This is a test file.
Practical example: Configuration file
#include <fstream>
#include <iostream>
#include <string>
#include <map>
class ConfigManager
{
private:
std::map<std::string, std::string> settings;
std::string filename;
public:
ConfigManager(const std::string& configFile) : filename(configFile) {}
bool loadConfig()
{
std::ifstream inFile(filename);
if (!inFile.is_open())
{
std::cout << "Config file not found. Creating default settings." << std::endl;
createDefaultConfig();
return true;
}
std::string line;
while (std::getline(inFile, line))
{
size_t pos = line.find('=');
if (pos != std::string::npos)
{
std::string key = line.substr(0, pos);
std::string value = line.substr(pos + 1);
settings[key] = value;
}
}
return true;
}
bool saveConfig()
{
std::ofstream outFile(filename);
if (!outFile.is_open())
{
std::cerr << "Error: Cannot save configuration file!" << std::endl;
return false;
}
for (const auto& pair : settings)
{
outFile << pair.first << "=" << pair.second << std::endl;
}
return true;
}
void setSetting(const std::string& key, const std::string& value)
{
settings[key] = value;
}
std::string getSetting(const std::string& key, const std::string& defaultValue = "")
{
auto it = settings.find(key);
return (it != settings.end()) ? it->second : defaultValue;
}
private:
void createDefaultConfig()
{
settings["username"] = "user";
settings["theme"] = "dark";
settings["language"] = "english";
settings["auto_save"] = "true";
}
};
int main()
{
ConfigManager config("app_config.txt");
// Load existing config or create default
config.loadConfig();
// Display current settings
std::cout << "Current settings:" << std::endl;
std::cout << "Username: " << config.getSetting("username") << std::endl;
std::cout << "Theme: " << config.getSetting("theme") << std::endl;
std::cout << "Language: " << config.getSetting("language") << std::endl;
std::cout << "Auto-save: " << config.getSetting("auto_save") << std::endl;
// Modify a setting
config.setSetting("theme", "light");
config.setSetting("username", "john_doe");
// Save changes
if (config.saveConfig())
{
std::cout << "\nConfiguration saved successfully!" << std::endl;
}
return 0;
}
Best practices for file I/O
1. Always check if files opened successfully
std::ifstream file("data.txt");
if (!file.is_open())
{
std::cerr << "Failed to open file!" << std::endl;
return 1;
}
2. Use RAII (files close automatically)
{
std::ofstream file("data.txt");
file << "data";
} // File automatically closed here
3. Handle errors gracefully
if (file.fail())
{
std::cerr << "I/O operation failed!" << std::endl;
}
4. Use appropriate file modes
std::ofstream logFile("log.txt", std::ios::app); // Append to existing log
Common pitfalls to avoid
- Not checking if file opened: Always verify
is_open()
or use boolean conversion - Forgetting to close files: Use RAII or explicit
close()
- Wrong file paths: Use absolute paths or ensure working directory is correct
- Not handling read errors: Check stream state after operations
- Binary vs. text mode confusion: Use
std::ios::binary
for binary files
Summary
File I/O in C++ uses stream classes (std::ifstream
, std::ofstream
, std::fstream
) that work similarly to console I/O. Always check if files open successfully, handle errors gracefully, and use appropriate file modes. File streams automatically close when they go out of scope, but you can close them explicitly if needed.
Quiz
- What's the difference between
std::ifstream
,std::ofstream
, andstd::fstream
? - How do you check if a file opened successfully?
- What happens if you try to read from a file that doesn't exist?
- What's the difference between
std::ios::out
andstd::ios::app
modes? - Why is it important to handle file I/O errors?
Practice exercises
-
Write a program that creates a text file with your favorite books (title, author, year) and then reads and displays them.
-
Create a simple log file manager that appends timestamped messages to a log file.
-
Write a program that reads a text file and counts the number of lines, words, and characters.
-
Create a simple grade book program that saves and loads student grades from a file.
Explore More Courses
Discover other available courses while this lesson is being prepared.
Browse CoursesLesson Discussion
Share your thoughts and questions