Skip to content

文件操作

文件操作是程序与外部存储交互的重要方式。本章将介绍C++的文件流类、文件读写操作和文件定位等内容。

文件流基础

cpp
#include <iostream>
#include <fstream>  // 文件流头文件
#include <string>
using namespace std;

/*
 * C++文件流类层次:
 * 
 * ios_base(基类)
 * └── ios
 *     ├── istream(输入流)
 *     │   └── ifstream(文件输入流)
 *     ├── ostream(输出流)
 *     │   └── ofstream(文件输出流)
 *     └── iostream(输入输出流)
 *         └── fstream(文件输入输出流)
 */

int main() {
    // ============ 文件打开模式 ============
    
    /*
     * 文件打开模式:
     * 
     * ios::in        - 读模式
     * ios::out       - 写模式
     * ios::app       - 追加模式
     * ios::ate       - 打开后定位到文件末尾
     * ios::trunc     - 截断文件(清空内容)
     * ios::binary    - 二进制模式
     * 
     * 可以组合使用:ios::out | ios::app
     */
    
    // ============ 写入文件 ============
    
    // 方式1:构造时打开
    ofstream outFile1("output1.txt");
    
    // 方式2:先创建再打开
    ofstream outFile2;
    outFile2.open("output2.txt");
    
    // 检查是否成功打开
    if (!outFile1) {
        cerr << "无法打开文件" << endl;
        return 1;
    }
    
    // 写入数据
    outFile1 << "Hello, File!" << endl;
    outFile1 << "这是第二行" << endl;
    outFile1 << "数字: " << 12345 << endl;
    
    // 关闭文件
    outFile1.close();
    outFile2.close();
    
    cout << "文件写入完成" << endl;
    
    
    // ============ 读取文件 ============
    
    ifstream inFile("output1.txt");
    
    if (!inFile) {
        cerr << "无法打开文件进行读取" << endl;
        return 1;
    }
    
    cout << "\n===== 读取文件内容 =====" << endl;
    
    // 方式1:逐行读取
    string line;
    while (getline(inFile, line)) {
        cout << line << endl;
    }
    
    inFile.close();
    
    
    // ============ 追加写入 ============
    
    ofstream appendFile("output1.txt", ios::app);
    
    if (appendFile) {
        appendFile << "\n这是追加的内容" << endl;
        appendFile.close();
        cout << "\n追加写入完成" << endl;
    }
    
    return 0;
}

文本文件操作

cpp
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;

int main() {
    // ============ 写入文本文件 ============
    
    ofstream outFile("students.txt");
    
    if (!outFile) {
        cerr << "无法创建文件" << endl;
        return 1;
    }
    
    // 写入表头
    outFile << "姓名\t年龄\t分数" << endl;
    outFile << "----\t----\t----" << endl;
    
    // 写入数据
    vector<tuple<string, int, double>> students = {
        {"张三", 20, 95.5},
        {"李四", 21, 88.0},
        {"王五", 19, 92.5}
    };
    
    for (const auto& student : students) {
        outFile << get<0>(student) << "\t"
                << get<1>(student) << "\t"
                << get<2>(student) << endl;
    }
    
    outFile.close();
    cout << "学生数据写入完成" << endl;
    
    
    // ============ 读取文本文件 ============
    
    ifstream inFile("students.txt");
    
    if (!inFile) {
        cerr << "无法打开文件" << endl;
        return 1;
    }
    
    cout << "\n===== 读取学生数据 =====" << endl;
    
    string line;
    int lineNum = 0;
    
    while (getline(inFile, line)) {
        lineNum++;
        
        // 跳过表头
        if (lineNum <= 2) {
            cout << line << endl;
            continue;
        }
        
        // 解析数据行
        istringstream iss(line);
        string name;
        int age;
        double score;
        
        if (iss >> name >> age >> score) {
            cout << "解析: " << name << ", " << age << "岁, " << score << "分" << endl;
        }
    }
    
    inFile.close();
    
    
    // ============ 读写同一个文件 ============
    
    fstream file("data.txt", ios::in | ios::out | ios::trunc);
    
    if (!file) {
        cerr << "无法打开文件" << endl;
        return 1;
    }
    
    // 写入数据
    file << "第一行" << endl;
    file << "第二行" << endl;
    file << "第三行" << endl;
    
    // 定位到文件开头
    file.seekg(0, ios::beg);
    
    // 读取数据
    cout << "\n===== 读写同一文件 =====" << endl;
    string content;
    while (getline(file, content)) {
        cout << content << endl;
    }
    
    file.close();
    
    return 0;
}

二进制文件操作

cpp
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

// 定义一个结构体
struct Person {
    char name[50];
    int age;
    double height;
};

int main() {
    // ============ 写入二进制文件 ============
    
    ofstream outFile("people.dat", ios::binary);
    
    if (!outFile) {
        cerr << "无法创建二进制文件" << endl;
        return 1;
    }
    
    // 准备数据
    Person people[] = {
        {"张三", 25, 175.5},
        {"李四", 30, 180.0},
        {"王五", 28, 172.0}
    };
    
    // 写入二进制数据
    // write(指针, 字节数)
    for (const auto& p : people) {
        outFile.write(reinterpret_cast<const char*>(&p), sizeof(Person));
    }
    
    outFile.close();
    cout << "二进制数据写入完成" << endl;
    
    
    // ============ 读取二进制文件 ============
    
    ifstream inFile("people.dat", ios::binary);
    
    if (!inFile) {
        cerr << "无法打开二进制文件" << endl;
        return 1;
    }
    
    cout << "\n===== 读取二进制数据 =====" << endl;
    
    Person p;
    while (inFile.read(reinterpret_cast<char*>(&p), sizeof(Person))) {
        cout << "姓名: " << p.name << endl;
        cout << "年龄: " << p.age << endl;
        cout << "身高: " << p.height << endl;
        cout << "---" << endl;
    }
    
    inFile.close();
    
    
    // ============ 文件定位 ============
    
    fstream file("people.dat", ios::in | ios::out | ios::binary);
    
    if (!file) {
        cerr << "无法打开文件" << endl;
        return 1;
    }
    
    // 获取文件大小
    file.seekg(0, ios::end);
    streampos fileSize = file.tellg();
    cout << "\n文件大小: " << fileSize << " 字节" << endl;
    
    // 定位到第二条记录
    file.seekg(sizeof(Person), ios::beg);
    
    Person p2;
    file.read(reinterpret_cast<char*>(&p2), sizeof(Person));
    cout << "\n第二条记录: " << p2.name << ", " << p2.age << "岁" << endl;
    
    // 修改第二条记录
    p2.age = 35;
    file.seekp(sizeof(Person), ios::beg);  // 定位写位置
    file.write(reinterpret_cast<char*>(&p2), sizeof(Person));
    
    file.close();
    
    cout << "\n修改完成" << endl;
    
    return 0;
}

文件操作实例

cpp
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;

// 文件复制函数
bool copyFile(const string& source, const string& dest) {
    ifstream src(source, ios::binary);
    ofstream dst(dest, ios::binary);
    
    if (!src || !dst) {
        return false;
    }
    
    // 使用迭代器复制
    dst << src.rdbuf();
    
    return true;
}

// 统计文件信息
void fileStats(const string& filename) {
    ifstream file(filename);
    
    if (!file) {
        cerr << "无法打开文件: " << filename << endl;
        return;
    }
    
    int lines = 0;
    int words = 0;
    int chars = 0;
    
    string line;
    while (getline(file, line)) {
        lines++;
        chars += line.length() + 1;  // +1 for newline
        
        // 统计单词数
        bool inWord = false;
        for (char c : line) {
            if (isspace(c)) {
                inWord = false;
            } else if (!inWord) {
                inWord = true;
                words++;
            }
        }
    }
    
    cout << "文件统计 (" << filename << "):" << endl;
    cout << "  行数: " << lines << endl;
    cout << "  单词数: " << words << endl;
    cout << "  字符数: " << chars << endl;
}

// 查找文件中的字符串
vector<int> findInFile(const string& filename, const string& target) {
    ifstream file(filename);
    vector<int> lineNumbers;
    
    if (!file) {
        return lineNumbers;
    }
    
    string line;
    int lineNum = 0;
    
    while (getline(file, line)) {
        lineNum++;
        if (line.find(target) != string::npos) {
            lineNumbers.push_back(lineNum);
        }
    }
    
    return lineNumbers;
}

int main() {
    // 创建测试文件
    ofstream testFile("test.txt");
    testFile << "Hello World" << endl;
    testFile << "This is a test file" << endl;
    testFile << "Hello C++" << endl;
    testFile << "Programming is fun" << endl;
    testFile << "Hello again" << endl;
    testFile.close();
    
    // 文件复制
    cout << "===== 文件复制 =====" << endl;
    if (copyFile("test.txt", "test_copy.txt")) {
        cout << "复制成功" << endl;
    }
    
    // 文件统计
    cout << "\n===== 文件统计 =====" << endl;
    fileStats("test.txt");
    
    // 查找字符串
    cout << "\n===== 查找字符串 =====" << endl;
    string target = "Hello";
    vector<int> found = findInFile("test.txt", target);
    
    cout << "\"" << target << "\" 出现在以下行: ";
    for (int n : found) {
        cout << n << " ";
    }
    cout << endl;
    
    return 0;
}

本章小结

本章学习了:

  • 文件流类:ifstream、ofstream、fstream
  • 打开模式:in、out、app、binary等
  • 文本文件:读写文本数据
  • 二进制文件:read、write、文件定位
  • 文件操作实例:复制、统计、查找

下一章,我们将学习内存管理,了解C++的动态内存分配。