C++基础学习——文件操作详解

一、文件流类概述

C++ 标准库提供了三个主要的文件流类:

  1. ifstream (输入文件流):用于从文件读取数据
  2. ofstream (输出文件流):用于向文件写入数据
  3. fstream (文件流):既可读又可写

这些类都继承自 iostream 类,因此可以使用 <<>> 操作符进行格式化I/O操作。

二、文件打开与关闭

1. 打开文件

cpp 复制代码
#include <fstream>
using namespace std;

// 方法1:先声明再打开
ofstream outFile;
outFile.open("output.txt");

// 方法2:声明时直接打开
ifstream inFile("input.txt");

// 方法3:使用fstream
fstream ioFile;
ioFile.open("data.txt", ios::in | ios::out);

2. 文件打开模式

模式标志 描述
ios::in 以读取方式打开
ios::out 以写入方式打开
ios::app 追加模式,所有写入都追加到文件末尾
ios::ate 打开文件后定位到文件末尾
ios::trunc 如果文件存在则清空内容
ios::binary 二进制模式

组合示例:

cpp 复制代码
// 以写入和追加模式打开
ofstream logFile("log.txt", ios::out | ios::app);

// 以读写和二进制模式打开
fstream dataFile("data.dat", ios::in | ios::out | ios::binary);

3. 关闭文件

cpp 复制代码
outFile.close();
inFile.close();
ioFile.close();

注意:虽然流对象析构时会自动关闭文件,但显式关闭是个好习惯。

三、文件状态检查

cpp 复制代码
ifstream file("data.txt");

if (file.is_open()) {
    // 文件成功打开
} else {
    // 文件打开失败
}

// 检查流状态
if (file.good()) {
    // 流状态良好
}

if (file.fail()) {
    // 操作失败(非致命错误)
}

if (file.bad()) {
    // 严重错误
}

if (file.eof()) {
    // 到达文件末尾
}

四、文本文件操作

1. 写入文本文件

cpp 复制代码
ofstream out("output.txt");
if (out.is_open()) {
    out << "第一行文本" << endl;
    out << 123 << " " << 3.14 << endl;
    out << "这是另一行文本" << endl;
    out.close();
} else {
    cerr << "无法打开文件!" << endl;
}

2. 读取文本文件

逐行读取:
cpp 复制代码
ifstream in("input.txt");
string line;
if (in.is_open()) {
    while (getline(in, line)) {
        cout << line << endl;
    }
    in.close();
}
逐词读取:
cpp 复制代码
ifstream in("input.txt");
string word;
if (in.is_open()) {
    while (in >> word) {
        cout << word << endl;
    }
    in.close();
}
格式化读取:
cpp 复制代码
ifstream in("data.txt");
int id;
double value;
string name;

if (in.is_open()) {
    while (in >> id >> value >> name) {
        cout << "ID: " << id << ", Value: " << value 
             << ", Name: " << name << endl;
    }
    in.close();
}

五、二进制文件操作

1. 写入二进制数据

cpp 复制代码
struct Record {
    int id;
    char name[50];
    double salary;
};

Record emp = {101, "John Doe", 4500.50};

ofstream out("employees.dat", ios::binary);
if (out.is_open()) {
    out.write(reinterpret_cast<char*>(&emp), sizeof(Record));
    out.close();
}

2. 读取二进制数据

cpp 复制代码
Record emp;
ifstream in("employees.dat", ios::binary);
if (in.is_open()) {
    in.read(reinterpret_cast<char*>(&emp), sizeof(Record));
    cout << "ID: " << emp.id << endl;
    cout << "Name: " << emp.name << endl;
    cout << "Salary: " << emp.salary << endl;
    in.close();
}

3. 二进制文件随机访问

cpp 复制代码
fstream file("data.dat", ios::in | ios::out | ios::binary);

// 写入多个记录
Record records[3] = {
    {101, "Alice", 5000},
    {102, "Bob", 6000},
    {103, "Charlie", 7000}
};

file.write(reinterpret_cast<char*>(records), 3 * sizeof(Record));

// 直接读取第二个记录
Record emp;
file.seekg(1 * sizeof(Record), ios::beg);
file.read(reinterpret_cast<char*>(&emp), sizeof(Record));

// 修改第三个记录
emp = {103, "David", 7500};
file.seekp(2 * sizeof(Record), ios::beg);
file.write(reinterpret_cast<char*>(&emp), sizeof(Record));

file.close();

六、文件定位

1. 获取当前位置

cpp 复制代码
streampos pos = file.tellg();  // 获取读取位置
streampos pos = file.tellp();  // 获取写入位置

2. 设置位置

cpp 复制代码
// 绝对定位
file.seekg(0, ios::beg);  // 移动到文件开头
file.seekg(0, ios::end);  // 移动到文件末尾

// 相对定位
file.seekg(10, ios::cur);  // 从当前位置向前移动10字节
file.seekg(-5, ios::cur);  // 从当前位置向后移动5字节

七、实用文件操作函数

1. 检查文件是否存在

cpp 复制代码
#include <sys/stat.h>

bool fileExists(const string& filename) {
    struct stat buffer;
    return (stat(filename.c_str(), &buffer) == 0);
}

2. 获取文件大小

cpp 复制代码
streampos getFileSize(const string& filename) {
    ifstream file(filename, ios::ate | ios::binary);
    return file.tellg();
}

3. 复制文件

cpp 复制代码
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;
}

4. 读取CSV文件

cpp 复制代码
void readCSV(const string& filename) {
    ifstream file(filename);
    string line;
    
    while (getline(file, line)) {
        stringstream ss(line);
        string cell;
        vector<string> row;
        
        while (getline(ss, cell, ',')) {
            row.push_back(cell);
        }
        
        // 处理行数据
        for (const auto& val : row) {
            cout << val << "\t";
        }
        cout << endl;
    }
}

八、错误处理最佳实践

cpp 复制代码
void processFile(const string& filename) {
    ifstream file(filename);
    
    if (!file) {
        cerr << "错误:无法打开文件 " << filename << endl;
        perror("原因");  // 打印系统错误信息
        return;
    }
    
    try {
        // 文件处理代码
        string line;
        while (getline(file, line)) {
            // 处理每一行
        }
        
        if (file.bad()) {
            throw runtime_error("读取文件时发生严重错误");
        }
        
        if (file.fail() && !file.eof()) {
            throw runtime_error("文件格式错误");
        }
    } 
    catch (const exception& e) {
        cerr << "错误: " << e.what() << endl;
        file.close();
        return;
    }
    
    file.close();
}

九、性能考虑

  1. 缓冲区大小:默认缓冲区大小可能不适合大文件操作,可以自定义:

    cpp 复制代码
    char buffer[8192];  // 8KB缓冲区
    ifstream file;
    file.rdbuf()->pubsetbuf(buffer, sizeof(buffer));
    file.open("largefile.dat");
  2. 二进制 vs 文本:二进制操作通常比文本操作更快,特别是对于大量数据。

  3. 内存映射文件:对于极大文件,考虑使用操作系统特定的内存映射文件API。

十、C++17 文件系统库

C++17 引入了 <filesystem> 库,提供了更高级的文件操作:

cpp 复制代码
#include <filesystem>
namespace fs = std::filesystem;

// 检查文件是否存在
if (fs::exists("test.txt")) {
    // 获取文件大小
    auto size = fs::file_size("test.txt");
    
    // 复制文件
    fs::copy("source.txt", "destination.txt");
    
    // 删除文件
    fs::remove("old_file.txt");
    
    // 遍历目录
    for (auto& entry : fs::directory_iterator(".")) {
        cout << entry.path() << endl;
    }
}

通过掌握这些文件操作技术,您可以在C++程序中高效地处理各种文件I/O任务。

相关推荐
里昆34 分钟前
【AI】Jupyterlab中数据集的位置和程序和Pycharm中的区别
人工智能·学习
im_AMBER1 小时前
学习日志18 python
python·学习
regret~1 小时前
【记录】C++生产者 / 消费者 案例
开发语言·c++
尘似鹤1 小时前
c++注意点(12)----设计模式(生成器)
c++·设计模式
m0_687399843 小时前
Ubuntu22 上,用C++ gSoap 创建一个简单的webservice
开发语言·c++
屁股割了还要学3 小时前
【C语言进阶】一篇文章教会你文件的读写
c语言·开发语言·数据结构·c++·学习·青少年编程
微露清风3 小时前
系统性学习C语言-第二十二讲-动态内存管理
c语言·开发语言·学习
Shingmc33 小时前
【C++】二叉搜索数
开发语言·c++
✎ ﹏梦醒͜ღ҉繁华落℘3 小时前
WPF高级学习(一)
学习·wpf
荒诞硬汉3 小时前
数组相关学习
java·学习