Coming Soon

This lesson is currently being developed

Basic file I/O

Read from and write to files.

Input and Output (I/O)
Chapter
Beginner
Difficulty
50min
Estimated Time

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

In Progress

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:

  1. std::ifstream - Input file stream (reading from files)
  2. std::ofstream - Output file stream (writing to files)
  3. 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 reading
  • std::ios::out - Open for writing
  • std::ios::app - Append to end of file
  • std::ios::trunc - Truncate file if it exists
  • std::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

  1. Not checking if file opened: Always verify is_open() or use boolean conversion
  2. Forgetting to close files: Use RAII or explicit close()
  3. Wrong file paths: Use absolute paths or ensure working directory is correct
  4. Not handling read errors: Check stream state after operations
  5. 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

  1. What's the difference between std::ifstream, std::ofstream, and std::fstream?
  2. How do you check if a file opened successfully?
  3. What happens if you try to read from a file that doesn't exist?
  4. What's the difference between std::ios::out and std::ios::app modes?
  5. Why is it important to handle file I/O errors?

Practice exercises

  1. Write a program that creates a text file with your favorite books (title, author, year) and then reads and displays them.

  2. Create a simple log file manager that appends timestamped messages to a log file.

  3. Write a program that reads a text file and counts the number of lines, words, and characters.

  4. Create a simple grade book program that saves and loads student grades from a file.

Continue Learning

Explore other available lessons while this one is being prepared.

View Course

Explore More Courses

Discover other available courses while this lesson is being prepared.

Browse Courses

Lesson Discussion

Share your thoughts and questions

💬

No comments yet. Be the first to share your thoughts!

Sign in to join the discussion