c++文件操作详解

C++ 提供了强大的文件操作功能,主要通过 <fstream> 头文件中的类来实现。以下是对C++文件操作的全面解析:

一、文件流类体系

C++ 文件操作基于流的概念,核心类包括:

类名描述继承自
fstream文件流(读写操作)iostream
ifstream输入文件流(读操作)istream
ofstream输出文件流(写操作)ostream
filebuf文件缓冲区streambuf

二、文件打开模式

文件打开模式通过位掩码常量指定,可组合使用:

模式标志描述
ios::in打开文件进行读取(ifstream默认)
ios::out打开文件进行写入(ofstream默认),会截断现有文件
ios::app追加模式,所有写入操作都在文件末尾进行
ios::ate打开文件后定位到文件末尾
ios::trunc如果文件存在,则截断文件(out模式默认启用)
ios::binary以二进制模式打开文件(避免文本转换)
ios::nocreate如果文件不存在,打开失败(非标准,建议用C++17文件系统)
ios::noreplace如果文件存在,打开失败(非标准)

三、文件基本操作

1. 打开文件

#include <fstream>

// 方式1:构造函数打开
std::ofstream outFile("output.txt", std::ios::out | std::ios::app);

// 方式2:open()方法打开
std::ifstream inFile;
inFile.open("input.txt", std::ios::in);

// 检查文件是否成功打开
if (!outFile.is_open()) {
    std::cerr << "Error opening file!" << std::endl;
    return 1;
}

2. 关闭文件

outFile.close();  // 显式关闭文件
inFile.close();   // 文件流析构时会自动关闭,但显式关闭是好习惯

3. 文件状态检查

if (inFile.fail()) {
    // 操作失败(如类型不匹配)
}

if (inFile.bad()) {
    // 严重错误(如磁盘故障)
}

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

if (inFile.good()) {
    // 一切正常
}

// 重置错误状态
inFile.clear();

四、文本文件操作

1. 写入文本文件

std::ofstream textOut("data.txt");
if (textOut) {
    textOut << "Line 1: Hello, World!\n";
    textOut << "Line 2: The answer is " << 42 << "\n";
    textOut << "Line 3: Pi ≈ " << 3.14159 << "\n";
}

2. 读取文本文件

std::ifstream textIn("data.txt");
if (textIn) {
    // 逐行读取
    std::string line;
    while (std::getline(textIn, line)) {
        std::cout << line << std::endl;
    }
    
    // 重置文件指针到开头
    textIn.clear();
    textIn.seekg(0);
    
    // 按单词读取
    std::string word;
    while (textIn >> word) {
        std::cout << word << " ";
    }
}

五、二进制文件操作

1. 写入二进制数据

struct Record {
    int id;
    char name[50];
    double balance;
};

Record records[3] = {
    {1, "Alice", 100.50},
    {2, "Bob", 250.75},
    {3, "Charlie", 500.25}
};

std::ofstream binOut("data.bin", std::ios::binary);
if (binOut) {
    binOut.write(reinterpret_cast<char*>(records), sizeof(records));
}

2. 读取二进制数据

std::ifstream binIn("data.bin", std::ios::binary);
if (binIn) {
    // 获取文件大小
    binIn.seekg(0, std::ios::end);
    size_t fileSize = binIn.tellg();
    binIn.seekg(0, std::ios::beg);
    
    // 计算记录数量
    size_t numRecords = fileSize / sizeof(Record);
    Record* readRecords = new Record[numRecords];
    
    // 读取数据
    binIn.read(reinterpret_cast<char*>(readRecords), fileSize);
    
    // 处理数据...
    delete[] readRecords;
}

六、文件定位

std::fstream file("data.txt", std::ios::in | std::ios::out);

if (file) {
    // 获取当前位置
    std::streampos pos = file.tellg();
    
    // 移动到文件开头
    file.seekg(0, std::ios::beg);
    
    // 移动到文件末尾
    file.seekg(0, std::ios::end);
    
    // 向前移动10字节
    file.seekg(10, std::ios::cur);
    
    // 向后移动5字节
    file.seekg(-5, std::ios::cur);
    
    // 移动到第100字节处
    file.seekg(100);
}

七、C++17 文件系统库

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

#include <filesystem>
namespace fs = std::filesystem;

// 创建目录
fs::create_directory("data");

// 复制文件
fs::copy_file("source.txt", "data/destination.txt");

// 检查文件属性
if (fs::exists("data.txt")) {
    std::cout << "File size: " << fs::file_size("data.txt") << " bytes\n";
    std::cout << "Last modified: " << fs::last_write_time("data.txt") << "\n";
}

// 遍历目录
for (const auto& entry : fs::directory_iterator(".")) {
    if (entry.is_regular_file()) {
        std::cout << "File: " << entry.path() << "\n";
    } else if (entry.is_directory()) {
        std::cout << "Directory: " << entry.path() << "\n";
    }
}

// 删除文件
fs::remove("old_data.txt");

// 递归删除目录
fs::remove_all("obsolete_data");

八、高级文件操作技巧

1. 内存映射文件(平台特定)

// Windows 示例
#include <windows.h>

HANDLE hFile = CreateFile("large.bin", GENERIC_READ, FILE_SHARE_READ, 
                          NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
char* data = (char*)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);

// 使用 data 指针访问文件内容...

UnmapViewOfFile(data);
CloseHandle(hMap);
CloseHandle(hFile);

2. 临时文件处理

#include <cstdio>

// 创建临时文件
FILE* tmpFile = tmpfile();
if (tmpFile) {
    fputs("Temporary data", tmpFile);
    rewind(tmpFile);
    
    char buffer[256];
    fgets(buffer, sizeof(buffer), tmpFile);
    std::cout << "Temp content: " << buffer << std::endl;
    
    fclose(tmpFile); // 自动删除
}

// 使用C++17文件系统
auto tempPath = fs::temp_directory_path() / "tempfile.tmp";
std::ofstream tempOut(tempPath);
// 使用临时文件...
fs::remove(tempPath); // 手动删除

九、错误处理与最佳实践

  1. 始终检查文件操作结果
if (!file) {
        // 处理错误
    }
  1. 使用RAII管理资源
{
	std::ofstream file("data.txt");
	// 使用文件...
} // 文件自动关闭
  1. 处理大文件
    #ifdef _WIN32
   // Windows 上处理大于2GB的文件
   std::ifstream bigFile("large.bin", std::ios::binary | std::ios::ate);
   bigFile.seekg(0, std::ios::beg);
   #endif
  1. 跨平台路径处理
// 使用C++17文件系统
    fs::path filePath = "data";
    filePath /= "subdir";
    filePath /= "file.txt";
    
    // 输出平台无关路径
    std::cout << "Path: " << filePath.generic_string() << std::endl;
  1. 异常处理
	std::ifstream file;
    file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
    
    try {
        file.open("important.txt");
        // 文件操作...
    } catch (const std::ios_base::failure& e) {
        std::cerr << "File error: " << e.what() << std::endl;
    }

十、性能优化建议

  1. 使用缓冲区
char buffer[4096];
    std::ifstream inFile("large.bin", std::ios::binary);
    while (inFile.read(buffer, sizeof(buffer))) {
        // 处理缓冲区数据
    }
  1. 减少文件打开/关闭次数
    • 批量处理文件操作
    • 复用文件流对象
  2. 使用内存映射处理大文件
    • 避免多次读写操作
    • 提供随机访问能力
  3. 异步文件I/O
#include <future>
   
   auto readFuture = std::async(std::launch::async, []{
       std::ifstream file("data.bin", std::ios::binary);
       // 读取操作...
   });
   
   // 主线程继续执行其他任务...
   readFuture.get(); // 等待读取完成
  1. 选择合适的打开模式

    • 二进制模式避免文本转换开销
    • 追加模式减少文件定位开销

总结

C++提供了丰富的文件操作功能:

  • 基础文本和二进制文件读写
  • 文件定位和状态管理
  • C++17强大的文件系统库
  • 高级技术如内存映射和异步I/O
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芒果敲代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值