Skip to content

C++ 文件和流

概述

C++提供了强大的I/O流系统来处理文件和数据流操作。流(Stream)是数据传输的抽象概念,文件操作是流的重要应用。本章介绍文件读写、流操作、格式化输入输出等内容。

📁 文件操作基础

文件读写

cpp
#include <iostream>
#include <fstream>
#include <string>

int main() {
    std::cout << "=== 基本文件操作 ===" << std::endl;
    
    // 写入文件
    std::ofstream outFile("example.txt");
    if (outFile.is_open()) {
        outFile << "Hello, World!" << std::endl;
        outFile << "这是第二行文本" << std::endl;
        outFile << "数字: " << 42 << std::endl;
        outFile.close();
        std::cout << "文件写入成功" << std::endl;
    }
    
    // 读取文件
    std::ifstream inFile("example.txt");
    if (inFile.is_open()) {
        std::string line;
        std::cout << "文件内容:" << std::endl;
        while (std::getline(inFile, line)) {
            std::cout << line << std::endl;
        }
        inFile.close();
    } else {
        std::cout << "无法打开文件" << std::endl;
    }
    
    return 0;
}

文件模式和状态

cpp
#include <iostream>
#include <fstream>
#include <string>

class FileHandler {
public:
    static void writeTextFile(const std::string& filename, const std::string& content) {
        std::ofstream file(filename, std::ios::out | std::ios::trunc);
        
        if (!file) {
            throw std::runtime_error("无法创建文件: " + filename);
        }
        
        file << content;
        
        if (file.fail()) {
            throw std::runtime_error("写入文件失败");
        }
        
        std::cout << "文件 " << filename << " 写入成功" << std::endl;
    }
    
    static std::string readTextFile(const std::string& filename) {
        std::ifstream file(filename, std::ios::in);
        
        if (!file) {
            throw std::runtime_error("无法打开文件: " + filename);
        }
        
        std::string content;
        std::string line;
        
        while (std::getline(file, line)) {
            content += line + "\n";
        }
        
        if (file.bad()) {
            throw std::runtime_error("读取文件时发生错误");
        }
        
        return content;
    }
    
    static void appendToFile(const std::string& filename, const std::string& content) {
        std::ofstream file(filename, std::ios::out | std::ios::app);
        
        if (!file) {
            throw std::runtime_error("无法打开文件进行追加: " + filename);
        }
        
        file << content;
        std::cout << "内容已追加到 " << filename << std::endl;
    }
};

int main() {
    std::cout << "=== 文件模式和状态 ===" << std::endl;
    
    try {
        // 写入文件
        FileHandler::writeTextFile("test.txt", "第一行内容\n第二行内容\n");
        
        // 读取文件
        std::string content = FileHandler::readTextFile("test.txt");
        std::cout << "读取的内容:\n" << content << std::endl;
        
        // 追加内容
        FileHandler::appendToFile("test.txt", "追加的内容\n");
        
        // 再次读取
        content = FileHandler::readTextFile("test.txt");
        std::cout << "追加后的内容:\n" << content << std::endl;
        
    } catch (const std::exception& e) {
        std::cout << "错误: " << e.what() << std::endl;
    }
    
    return 0;
}

🌊 流操作

字符串流

cpp
#include <iostream>
#include <sstream>
#include <string>

class StringStreamDemo {
public:
    static void inputStringStream() {
        std::cout << "=== 输入字符串流 ===" << std::endl;
        
        std::string data = "123 45.67 hello world";
        std::istringstream iss(data);
        
        int num;
        double decimal;
        std::string word1, word2;
        
        iss >> num >> decimal >> word1 >> word2;
        
        std::cout << "整数: " << num << std::endl;
        std::cout << "小数: " << decimal << std::endl;
        std::cout << "单词1: " << word1 << std::endl;
        std::cout << "单词2: " << word2 << std::endl;
    }
    
    static void outputStringStream() {
        std::cout << "\n=== 输出字符串流 ===" << std::endl;
        
        std::ostringstream oss;
        oss << "数字: " << 42;
        oss << ", 小数: " << 3.14159;
        oss << ", 文本: " << "Hello";
        
        std::string result = oss.str();
        std::cout << "格式化结果: " << result << std::endl;
    }
    
    static std::string formatMessage(const std::string& name, int age, double salary) {
        std::ostringstream oss;
        oss << "员工信息 - 姓名: " << name 
            << ", 年龄: " << age 
            << ", 薪资: $" << std::fixed << std::setprecision(2) << salary;
        return oss.str();
    }
};

int main() {
    StringStreamDemo::inputStringStream();
    StringStreamDemo::outputStringStream();
    
    std::string info = StringStreamDemo::formatMessage("张三", 28, 5500.50);
    std::cout << "\n格式化信息: " << info << std::endl;
    
    return 0;
}

📋 格式化输入输出

流格式控制

cpp
#include <iostream>
#include <iomanip>
#include <fstream>

class FormatDemo {
public:
    static void numberFormatting() {
        std::cout << "=== 数字格式化 ===" << std::endl;
        
        double pi = 3.141592653589793;
        int num = 42;
        
        // 精度控制
        std::cout << std::setprecision(3) << pi << std::endl;
        std::cout << std::setprecision(6) << pi << std::endl;
        
        // 固定小数点
        std::cout << std::fixed << std::setprecision(2) << pi << std::endl;
        
        // 科学记数法
        std::cout << std::scientific << pi << std::endl;
        
        // 字段宽度和对齐
        std::cout << std::setw(10) << std::left << num << "|" << std::endl;
        std::cout << std::setw(10) << std::right << num << "|" << std::endl;
        std::cout << std::setw(10) << std::setfill('0') << num << "|" << std::endl;
        
        // 进制输出
        std::cout << "十进制: " << std::dec << num << std::endl;
        std::cout << "十六进制: " << std::hex << num << std::endl;
        std::cout << "八进制: " << std::oct << num << std::endl;
    }
    
    static void tableFormatting() {
        std::cout << "\n=== 表格格式化 ===" << std::endl;
        
        struct Student {
            std::string name;
            int age;
            double gpa;
        };
        
        std::vector<Student> students = {
            {"Alice", 20, 3.85},
            {"Bob", 19, 3.92},
            {"Charlie", 21, 3.67}
        };
        
        // 表头
        std::cout << std::left << std::setw(10) << "姓名" 
                  << std::setw(6) << "年龄" 
                  << std::setw(8) << "GPA" << std::endl;
        
        std::cout << std::string(24, '-') << std::endl;
        
        // 表格内容
        for (const auto& student : students) {
            std::cout << std::left << std::setw(10) << student.name
                      << std::setw(6) << student.age
                      << std::fixed << std::setprecision(2) << student.gpa << std::endl;
        }
    }
};

int main() {
    FormatDemo::numberFormatting();
    FormatDemo::tableFormatting();
    
    return 0;
}

📊 二进制文件操作

二进制读写

cpp
#include <iostream>
#include <fstream>
#include <vector>
#include <cstring>

struct Person {
    char name[50];
    int age;
    double salary;
    
    Person() = default;
    Person(const std::string& n, int a, double s) : age(a), salary(s) {
        std::strncpy(name, n.c_str(), sizeof(name) - 1);
        name[sizeof(name) - 1] = '\0';
    }
    
    void display() const {
        std::cout << "姓名: " << name << ", 年龄: " << age 
                  << ", 薪资: " << salary << std::endl;
    }
};

class BinaryFileHandler {
public:
    static void writePersons(const std::string& filename, const std::vector<Person>& persons) {
        std::ofstream file(filename, std::ios::binary);
        
        if (!file) {
            throw std::runtime_error("无法创建二进制文件");
        }
        
        for (const auto& person : persons) {
            file.write(reinterpret_cast<const char*>(&person), sizeof(Person));
        }
        
        std::cout << "写入 " << persons.size() << " 个记录到 " << filename << std::endl;
    }
    
    static std::vector<Person> readPersons(const std::string& filename) {
        std::ifstream file(filename, std::ios::binary);
        
        if (!file) {
            throw std::runtime_error("无法打开二进制文件");
        }
        
        std::vector<Person> persons;
        Person person;
        
        while (file.read(reinterpret_cast<char*>(&person), sizeof(Person))) {
            persons.push_back(person);
        }
        
        std::cout << "从 " << filename << " 读取 " << persons.size() << " 个记录" << std::endl;
        return persons;
    }
};

int main() {
    std::cout << "=== 二进制文件操作 ===" << std::endl;
    
    try {
        // 创建数据
        std::vector<Person> persons = {
            Person("张三", 25, 5000.0),
            Person("李四", 30, 6000.0),
            Person("王五", 28, 5500.0)
        };
        
        // 写入二进制文件
        BinaryFileHandler::writePersons("persons.dat", persons);
        
        // 读取二进制文件
        auto readPersons = BinaryFileHandler::readPersons("persons.dat");
        
        std::cout << "\n读取的数据:" << std::endl;
        for (const auto& person : readPersons) {
            person.display();
        }
        
    } catch (const std::exception& e) {
        std::cout << "错误: " << e.what() << std::endl;
    }
    
    return 0;
}

总结

C++的文件和流系统提供了灵活强大的I/O处理能力:

流类型

  • ifstream: 输入文件流
  • ofstream: 输出文件流
  • fstream: 双向文件流
  • stringstream: 字符串流

文件模式

模式说明用途
ios::in读取模式打开文件读取
ios::out写入模式打开文件写入
ios::app追加模式在文件末尾追加
ios::binary二进制模式二进制读写

最佳实践

  • 及时关闭文件或使用RAII
  • 检查文件操作状态
  • 适当的异常处理
  • 选择合适的文件模式
  • 注意二进制和文本模式的区别

文件和流操作是C++程序与外部数据交互的重要途径。

本站内容仅供学习和研究使用。