Coming Soon
This lesson is currently being developed
File Basics
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.
Basic file I/O
In this lesson, you'll learn how to work with files in C++ using file streams. You'll discover how to read from and write to files, handle different file modes, and implement proper error checking for file operations.
Introduction to file streams
File streams allow you to read from and write to files on disk using the same stream operations you've learned for console I/O. C++ provides three main file stream classes:
std::ifstream- Input file stream (reading from files)std::ofstream- Output file stream (writing to files)std::fstream- File stream (both reading and writing)
#include <iostream>
#include <fstream>
int main()
{
std::ofstream outputFile("hello.txt");
if (outputFile.is_open())
{
outputFile << "Hello, World!" << std::endl;
outputFile << "This is written to a file." << std::endl;
outputFile.close();
std::cout << "File written successfully!" << std::endl;
}
else
{
std::cout << "Unable to open file!" << std::endl;
}
return 0;
}
Output:
File written successfully!
File contents (hello.txt):
Hello, World!
This is written to a file.
Writing to files with ofstream
Basic file writing
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::ofstream outputFile("student_data.txt");
if (!outputFile)
{
std::cerr << "Error: Cannot create file!" << std::endl;
return 1;
}
// Write different types of data
std::string name = "Alice Johnson";
int age = 20;
double gpa = 3.75;
outputFile << "Student Information" << std::endl;
outputFile << "==================" << std::endl;
outputFile << "Name: " << name << std::endl;
outputFile << "Age: " << age << std::endl;
outputFile << "GPA: " << std::fixed << std::setprecision(2) << gpa << std::endl;
outputFile.close();
std::cout << "Student data written to file." << std::endl;
return 0;
}
File contents (student_data.txt):
Student Information
==================
Name: Alice Johnson
Age: 20
GPA: 3.75
Writing multiple records
#include <iostream>
#include <fstream>
#include <vector>
#include <iomanip>
struct Student
{
std::string name;
int age;
double gpa;
};
int main()
{
std::vector<Student> students = {
{"Alice Johnson", 20, 3.75},
{"Bob Smith", 19, 3.92},
{"Charlie Brown", 21, 3.58}
};
std::ofstream file("students.txt");
if (!file)
{
std::cerr << "Error: Cannot create file!" << std::endl;
return 1;
}
// Write header
file << std::left << std::setw(15) << "Name"
<< std::setw(5) << "Age"
<< "GPA" << std::endl;
file << std::string(25, '-') << std::endl;
// Write student data
for (const auto& student : students)
{
file << std::left << std::setw(15) << student.name
<< std::setw(5) << student.age
<< std::fixed << std::setprecision(2) << student.gpa << std::endl;
}
file.close();
std::cout << "Student records written to file." << std::endl;
return 0;
}
File contents (students.txt):
Name Age GPA
-------------------------
Alice Johnson 20 3.75
Bob Smith 19 3.92
Charlie Brown 21 3.58
Reading from files with ifstream
Basic file reading
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::ifstream inputFile("student_data.txt");
if (!inputFile)
{
std::cerr << "Error: Cannot open file!" << std::endl;
return 1;
}
std::string line;
std::cout << "File contents:" << std::endl;
while (std::getline(inputFile, line))
{
std::cout << line << std::endl;
}
inputFile.close();
return 0;
}
Output:
File contents:
Student Information
==================
Name: Alice Johnson
Age: 20
GPA: 3.75
Reading structured data
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
struct Product
{
std::string name;
double price;
int quantity;
};
std::vector<Product> readProductsFromCSV(const std::string& filename)
{
std::vector<Product> products;
std::ifstream file(filename);
if (!file)
{
std::cerr << "Error: Cannot open file " << filename << std::endl;
return products;
}
std::string line;
// Skip header line
std::getline(file, line);
while (std::getline(file, line))
{
std::stringstream ss(line);
std::string name, priceStr, quantityStr;
if (std::getline(ss, name, ',') &&
std::getline(ss, priceStr, ',') &&
std::getline(ss, quantityStr, ','))
{
Product product;
product.name = name;
product.price = std::stod(priceStr);
product.quantity = std::stoi(quantityStr);
products.push_back(product);
}
}
file.close();
return products;
}
int main()
{
// First, create a sample CSV file
std::ofstream csvFile("products.csv");
csvFile << "Name,Price,Quantity" << std::endl;
csvFile << "Laptop,999.99,10" << std::endl;
csvFile << "Mouse,25.50,50" << std::endl;
csvFile << "Keyboard,75.00,30" << std::endl;
csvFile.close();
// Now read the products
std::vector<Product> products = readProductsFromCSV("products.csv");
std::cout << "Products loaded from file:" << std::endl;
std::cout << std::left << std::setw(15) << "Name"
<< std::setw(10) << "Price"
<< "Quantity" << std::endl;
std::cout << std::string(30, '-') << std::endl;
for (const auto& product : products)
{
std::cout << std::left << std::setw(15) << product.name
<< std::setw(10) << product.price
<< product.quantity << std::endl;
}
return 0;
}
Output:
Products loaded from file:
Name Price Quantity
------------------------------
Laptop 999.99 10
Mouse 25.5 50
Keyboard 75 30
File opening modes
File streams can be opened in different modes to control how they behave:
#include <iostream>
#include <fstream>
int main()
{
// Different ways to open files
// 1. Default mode - truncate existing file
std::ofstream file1("output.txt");
file1 << "This overwrites existing content" << std::endl;
file1.close();
// 2. Append mode - add to end of existing file
std::ofstream file2("output.txt", std::ios::app);
file2 << "This is appended to the file" << std::endl;
file2.close();
// 3. Binary mode
std::ofstream binaryFile("data.bin", std::ios::binary);
int numbers[] = {1, 2, 3, 4, 5};
binaryFile.write(reinterpret_cast<const char*>(numbers), sizeof(numbers));
binaryFile.close();
// 4. Read and write mode
std::fstream readWriteFile("readwrite.txt", std::ios::in | std::ios::out | std::ios::trunc);
readWriteFile << "Initial content" << std::endl;
readWriteFile.seekg(0); // Go to beginning
std::string content;
std::getline(readWriteFile, content);
std::cout << "Read: " << content << std::endl;
readWriteFile.close();
return 0;
}
Output:
Read: Initial content
File contents (output.txt):
This overwrites existing content
This is appended to the file
File mode flags
#include <iostream>
#include <fstream>
void demonstrateFileModes()
{
// ios::in - Open for reading
std::ifstream inFile("input.txt", std::ios::in);
// ios::out - Open for writing (default for ofstream)
std::ofstream outFile("output.txt", std::ios::out);
// ios::app - Append to end of file
std::ofstream appendFile("log.txt", std::ios::app);
// ios::trunc - Truncate file to zero length (default with ios::out)
std::ofstream truncFile("temp.txt", std::ios::trunc);
// ios::binary - Open in binary mode
std::ofstream binFile("data.bin", std::ios::binary);
// Combined modes
std::fstream rwFile("data.txt", std::ios::in | std::ios::out | std::ios::app);
// Close files
inFile.close();
outFile.close();
appendFile.close();
truncFile.close();
binFile.close();
rwFile.close();
}
int main()
{
demonstrateFileModes();
std::cout << "File modes demonstrated." << std::endl;
return 0;
}
Error handling with file streams
Checking if file operations succeed
#include <iostream>
#include <fstream>
bool writeToFile(const std::string& filename, const std::string& content)
{
std::ofstream file(filename);
if (!file.is_open())
{
std::cerr << "Error: Cannot open file '" << filename << "' for writing." << std::endl;
return false;
}
file << content;
if (file.fail())
{
std::cerr << "Error: Failed to write to file '" << filename << "'." << std::endl;
file.close();
return false;
}
file.close();
if (file.fail())
{
std::cerr << "Error: Failed to close file '" << filename << "'." << std::endl;
return false;
}
return true;
}
std::string readFromFile(const std::string& filename, bool& success)
{
std::ifstream file(filename);
success = false;
if (!file.is_open())
{
std::cerr << "Error: Cannot open file '" << filename << "' for reading." << std::endl;
return "";
}
std::string content, line;
while (std::getline(file, line))
{
content += line + "\n";
}
if (file.bad())
{
std::cerr << "Error: Failed to read from file '" << filename << "'." << std::endl;
file.close();
return "";
}
file.close();
success = true;
return content;
}
int main()
{
std::string filename = "test.txt";
std::string content = "Hello, file I/O!\nThis is a test.";
// Write to file
if (writeToFile(filename, content))
{
std::cout << "Successfully wrote to file." << std::endl;
// Read from file
bool success;
std::string readContent = readFromFile(filename, success);
if (success)
{
std::cout << "File contents:" << std::endl;
std::cout << readContent << std::endl;
}
}
return 0;
}
Output:
Successfully wrote to file.
File contents:
Hello, file I/O!
This is a test.
Working with binary files
Writing binary data
#include <iostream>
#include <fstream>
struct Person
{
char name[50];
int age;
double salary;
};
int main()
{
// Create some data
Person people[] = {
{"Alice Johnson", 28, 75000.50},
{"Bob Smith", 32, 82000.00},
{"Charlie Brown", 25, 68000.75}
};
// Write binary data
std::ofstream binFile("people.dat", std::ios::binary);
if (!binFile)
{
std::cerr << "Error: Cannot create binary file!" << std::endl;
return 1;
}
// Write the number of records first
int count = sizeof(people) / sizeof(Person);
binFile.write(reinterpret_cast<const char*>(&count), sizeof(count));
// Write the person records
binFile.write(reinterpret_cast<const char*>(people), sizeof(people));
binFile.close();
std::cout << "Binary data written successfully." << std::endl;
return 0;
}
Reading binary data
#include <iostream>
#include <fstream>
#include <iomanip>
struct Person
{
char name[50];
int age;
double salary;
};
int main()
{
std::ifstream binFile("people.dat", std::ios::binary);
if (!binFile)
{
std::cerr << "Error: Cannot open binary file!" << std::endl;
return 1;
}
// Read the number of records
int count;
binFile.read(reinterpret_cast<char*>(&count), sizeof(count));
if (binFile.gcount() != sizeof(count))
{
std::cerr << "Error: Failed to read record count!" << std::endl;
return 1;
}
std::cout << "Reading " << count << " records:" << std::endl;
std::cout << std::left << std::setw(20) << "Name"
<< std::setw(5) << "Age"
<< "Salary" << std::endl;
std::cout << std::string(35, '-') << std::endl;
// Read each person record
for (int i = 0; i < count; ++i)
{
Person person;
binFile.read(reinterpret_cast<char*>(&person), sizeof(person));
if (binFile.gcount() != sizeof(person))
{
std::cerr << "Error: Failed to read person record " << i << std::endl;
break;
}
std::cout << std::left << std::setw(20) << person.name
<< std::setw(5) << person.age
<< std::fixed << std::setprecision(2) << person.salary << std::endl;
}
binFile.close();
return 0;
}
Output:
Reading 3 records:
Name Age Salary
-----------------------------------
Alice Johnson 28 75000.50
Bob Smith 32 82000.00
Charlie Brown 25 68000.75
File utility functions
Checking if file exists
#include <iostream>
#include <fstream>
bool fileExists(const std::string& filename)
{
std::ifstream file(filename);
return file.good();
}
long getFileSize(const std::string& filename)
{
std::ifstream file(filename, std::ios::binary | std::ios::ate);
if (!file)
{
return -1; // File doesn't exist or cannot be opened
}
return file.tellg();
}
int countLines(const std::string& filename)
{
std::ifstream file(filename);
if (!file)
{
return -1; // File doesn't exist or cannot be opened
}
int lines = 0;
std::string line;
while (std::getline(file, line))
{
++lines;
}
return lines;
}
int main()
{
std::string filename = "test.txt";
// Create a test file
std::ofstream testFile(filename);
testFile << "Line 1\n";
testFile << "Line 2\n";
testFile << "Line 3\n";
testFile.close();
// Test utility functions
if (fileExists(filename))
{
std::cout << "File '" << filename << "' exists." << std::endl;
std::cout << "File size: " << getFileSize(filename) << " bytes" << std::endl;
std::cout << "Line count: " << countLines(filename) << " lines" << std::endl;
}
else
{
std::cout << "File '" << filename << "' does not exist." << std::endl;
}
return 0;
}
Output:
File 'test.txt' exists.
File size: 21 bytes
Line count: 3 lines
Practical file I/O examples
Simple logging system
#include <iostream>
#include <fstream>
#include <chrono>
#include <iomanip>
class Logger
{
private:
std::ofstream logFile;
std::string getCurrentTimestamp()
{
auto now = std::chrono::system_clock::now();
auto time_t = std::chrono::system_clock::to_time_t(now);
std::ostringstream oss;
oss << std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S");
return oss.str();
}
public:
Logger(const std::string& filename)
{
logFile.open(filename, std::ios::app);
if (!logFile)
{
std::cerr << "Error: Cannot open log file!" << std::endl;
}
}
~Logger()
{
if (logFile.is_open())
{
logFile.close();
}
}
void log(const std::string& level, const std::string& message)
{
if (logFile.is_open())
{
logFile << "[" << getCurrentTimestamp() << "] "
<< "[" << level << "] "
<< message << std::endl;
}
}
void info(const std::string& message) { log("INFO", message); }
void warning(const std::string& message) { log("WARNING", message); }
void error(const std::string& message) { log("ERROR", message); }
};
int main()
{
Logger logger("application.log");
logger.info("Application started");
logger.warning("This is a warning message");
logger.error("This is an error message");
logger.info("Application ended");
std::cout << "Log entries written to application.log" << std::endl;
return 0;
}
Configuration file handler
#include <iostream>
#include <fstream>
#include <map>
#include <sstream>
class ConfigManager
{
private:
std::map<std::string, std::string> config;
std::string filename;
public:
ConfigManager(const std::string& configFile) : filename(configFile)
{
loadConfig();
}
bool loadConfig()
{
std::ifstream file(filename);
if (!file)
{
std::cerr << "Warning: Cannot open config file. Using defaults." << std::endl;
return false;
}
std::string line;
while (std::getline(file, line))
{
// Skip empty lines and comments
if (line.empty() || line[0] == '#')
continue;
size_t pos = line.find('=');
if (pos != std::string::npos)
{
std::string key = line.substr(0, pos);
std::string value = line.substr(pos + 1);
// Trim whitespace (simplified)
key.erase(key.find_last_not_of(" \t") + 1);
value.erase(0, value.find_first_not_of(" \t"));
config[key] = value;
}
}
file.close();
return true;
}
bool saveConfig()
{
std::ofstream file(filename);
if (!file)
{
std::cerr << "Error: Cannot write to config file!" << std::endl;
return false;
}
file << "# Application Configuration" << std::endl;
for (const auto& pair : config)
{
file << pair.first << " = " << pair.second << std::endl;
}
file.close();
return true;
}
void setString(const std::string& key, const std::string& value)
{
config[key] = value;
}
void setInt(const std::string& key, int value)
{
config[key] = std::to_string(value);
}
std::string getString(const std::string& key, const std::string& defaultValue = "")
{
auto it = config.find(key);
return (it != config.end()) ? it->second : defaultValue;
}
int getInt(const std::string& key, int defaultValue = 0)
{
auto it = config.find(key);
if (it != config.end())
{
try
{
return std::stoi(it->second);
}
catch (...)
{
return defaultValue;
}
}
return defaultValue;
}
void printConfig()
{
std::cout << "Current configuration:" << std::endl;
for (const auto& pair : config)
{
std::cout << pair.first << " = " << pair.second << std::endl;
}
}
};
int main()
{
ConfigManager config("app.conf");
// Set some configuration values
config.setString("app_name", "My Application");
config.setString("version", "1.0.0");
config.setInt("max_connections", 100);
config.setInt("timeout", 30);
// Save configuration
config.saveConfig();
// Display current configuration
config.printConfig();
// Demonstrate reading values
std::cout << "\nReading configuration:" << std::endl;
std::cout << "App Name: " << config.getString("app_name") << std::endl;
std::cout << "Max Connections: " << config.getInt("max_connections") << std::endl;
return 0;
}
Best practices for file I/O
✅ Good practices:
#include <iostream>
#include <fstream>
int main()
{
// Always check if file operations succeed
std::ofstream file("output.txt");
if (!file.is_open())
{
std::cerr << "Error: Cannot open file!" << std::endl;
return 1;
}
// Use RAII - file will be automatically closed
file << "Content written to file" << std::endl;
// Check for write errors
if (file.fail())
{
std::cerr << "Error: Write operation failed!" << std::endl;
return 1;
}
// File automatically closed when going out of scope
return 0;
}
❌ Common mistakes:
#include <iostream>
#include <fstream>
int main()
{
// Bad: Not checking if file opened successfully
std::ofstream file("output.txt");
file << "This might not work!" << std::endl; // Could fail silently
// Bad: Not closing files (though destructors will do it)
std::ifstream input("input.txt");
// ... use file but never explicitly close
// Bad: Not handling errors
std::ifstream data("data.txt");
int value;
data >> value; // What if this fails?
std::cout << value << std::endl; // Could be garbage
return 0;
}
Summary
Basic file I/O in C++ involves:
- File stream classes:
std::ifstream,std::ofstream, andstd::fstream - Opening files: Using constructors or the
open()method - File modes: Controlling how files are opened (read, write, append, binary)
- Error checking: Always verify that file operations succeed
- Reading techniques: Line-by-line, structured data, and binary reading
- Writing techniques: Text output, formatted data, and binary writing
- File utilities: Checking existence, getting size, counting lines
- RAII principle: Files are automatically closed when objects go out of scope
File I/O is essential for creating practical applications that can store and retrieve data persistently.
Quiz
- What's the difference between
std::ifstream,std::ofstream, andstd::fstream? - How do you check if a file was opened successfully?
- What file mode would you use to add data to the end of an existing file?
- Why is it important to check the success of file operations?
- What happens to file handles when file stream objects go out of scope?
Practice exercises
Apply your file I/O knowledge with these exercises:
-
Student Grade Manager: Create a program that can save student names and grades to a file, then read them back and calculate class statistics.
-
Simple Database: Build a program that stores product information (name, price, quantity) in a file and provides functions to add, search, and update records.
-
Log File Analyzer: Write a program that reads a log file and generates a summary report showing different types of log entries and their frequencies.
-
Configuration Backup: Create a system that automatically backs up configuration files by copying them with timestamps in the filename.
Explore More Courses
Discover other available courses while this lesson is being prepared.
Browse CoursesLesson Discussion
Share your thoughts and questions