C++ 文件操作详解

C++ 文件操作详解

一、C++ 文件操作详解

C++ 主要通过 <fstream> 头文件中定义的流类来进行文件操作。这些类继承自 <iostream> 中的标准输入输出流类,因此其使用方式与 cincout 非常相似。

1、核心类

  1. std::ofstream (输出文件流): 用于向文件写入数据。
  2. std::ifstream (输入文件流): 用于从文件读取数据。
  3. std::fstream (文件流): 可以同时进行读写操作(取决于打开方式)。

2、文件打开模式 (Open Modes)

打开文件时,可以指定文件的操作模式。这些模式是位掩码常量,定义在 std::ios_base 命名空间中,通常使用 std::ios 作为别名。常用模式有:

  • std::ios::in: 以读取方式打开(ifstream 默认)。
  • std::ios::out: 以写入方式打开,会覆盖原有内容(ofstream 默认)。
  • std::ios::app: 以追加方式打开,所有写入都追加到文件末尾。
  • std::ios::ate: 打开文件后,立即定位到文件末尾。
  • std::ios::trunc: 如果文件存在,先将其内容清空(out 模式默认包含)。
  • std::ios::binary: 以二进制模式打开文件(默认是文本模式)。

模式可以组合使用,例如:

cpp 复制代码
std::fstream file("data.txt", std::ios::in | std::ios::out); // 读写模式
std::ofstream outfile("log.txt", std::ios::app); // 追加模式

3、基本操作流程

  1. 打开文件:

    • 在创建流对象时通过构造函数指定文件名和模式。
    cpp 复制代码
    std::ofstream outfile("output.txt"); // 默认 out + trunc
    std::ifstream infile("input.txt"); // 默认 in
    • 或者先创建对象,再调用 open() 方法。
    cpp 复制代码
    std::fstream file;
    file.open("data.dat", std::ios::in | std::ios::out | std::ios::binary);
  2. 检查文件是否成功打开:

    在尝试读写之前,务必检查文件是否成功打开。

    cpp 复制代码
    if (!outfile.is_open()) { // 或者 if (!outfile)
        std::cerr << "打开文件失败!" << std::endl;
        // 处理错误
        return;
    }
  3. 读写文件:

    • 文本文件: 使用 << (输出流) 和 >> (输入流) 运算符,或者 get()getline()put() 等成员函数,就像操作 coutcin 一样。

      cpp 复制代码
      // 写入文本
      outfile << "姓名: " << name << std::endl;
      outfile << "年龄: " << age << std::endl;
      
      // 读取文本
      std::string line;
      while (std::getline(infile, line)) { // 逐行读取
          std::cout << line << std::endl;
      }
      
      int value;
      infile >> value; // 读取一个整数
    • 二进制文件: 使用 read()write() 成员函数。它们直接操作内存块。

      cpp 复制代码
      // 写入二进制数据 (例如一个结构体)
      struct Person {
          char name[50];
          int age;
      } p = {"张三", 30};
      
      outfile.write(reinterpret_cast<char*>(&p), sizeof(p));
      
      // 读取二进制数据
      Person p_read;
      infile.read(reinterpret_cast<char*>(&p_read), sizeof(p_read));

      注意: 二进制模式读写不进行任何格式转换(如换行符转换),直接读写字节。reinterpret_cast<char*> 用于将对象指针转换为 char* 指针,因为 read/write 操作的是字节 (char)。

  4. 文件定位:

    • tellg(): 返回输入流的当前位置指针(读位置)。
    • tellp(): 返回输出流的当前位置指针(写位置)。
    • seekg(offset, direction): 设置输入流的位置指针。
    • seekp(offset, direction): 设置输出流的位置指针。
      方向 (direction):
    • std::ios::beg: 文件开头 (默认)。
    • std::ios::cur: 当前位置。
    • std::ios::end: 文件末尾。
    cpp 复制代码
    infile.seekg(0, std::ios::end); // 定位到文件末尾
    std::streampos size = infile.tellg(); // 获取文件大小
    infile.seekg(0, std::ios::beg); // 重新定位到开头
  5. 关闭文件:

    当流对象离开其作用域时,析构函数会自动关闭文件。但显式关闭是一个好习惯,特别是需要立即释放资源或重新打开文件时。

    cpp 复制代码
    outfile.close();
    infile.close();

4、错误处理

除了检查 is_open(),还可以使用以下方法检查流状态:

  • good(): 流状态正常 (无错误)。
  • eof(): 到达文件末尾。
  • fail(): 发生非致命错误(可恢复,如格式错误)。
  • bad(): 发生致命错误(流可能损坏)。
    通常:
cpp 复制代码
if (infile.fail() && !infile.eof()) {
    // 处理读取错误 (非EOF导致)
}
// 或者
while (infile >> data) { // 操作成功且未到EOF时,条件为true
    // 处理数据
}

5、 示例代码

  1. 写入文本文件:
cpp 复制代码
#include <iostream>
#include <fstream>

int main() {
    std::ofstream outfile("example.txt");
    if (!outfile) {
        std::cerr << "创建文件失败!" << std::endl;
        return 1;
    }
    outfile << "Hello, File World!\n";
    outfile << "This is a line of text.\n";
    outfile << 42 << " " << 3.14159 << std::endl;
    outfile.close();
    return 0;
}

运行:

  1. 读取文本文件:
cpp 复制代码
#include <iostream>
#include <fstream>
#include <string>

int main() {
    std::ifstream infile("example.txt");
    if (!infile) {
        std::cerr << "打开文件失败!" << std::endl;
        return 1;
    }
    std::string line;
    while (std::getline(infile, line)) {
        std::cout << line << std::endl;
    }
    infile.close();
    return 0;
}

运行:

  1. 读写二进制文件:
cpp 复制代码
#include <iostream>
#include <fstream>

struct Point {
    double x, y;
};

int main() {
    // 写入二进制
    Point p1 = {1.0, 2.0}, p2 = {3.0, 4.0};
    std::ofstream outbin("points.dat", std::ios::binary);
    if (!outbin) return 1;
    outbin.write(reinterpret_cast<char*>(&p1), sizeof(Point));
    outbin.write(reinterpret_cast<char*>(&p2), sizeof(Point));
    outbin.close();

    // 读取二进制
    Point p_read;
    std::ifstream inbin("points.dat", std::ios::binary);
    if (!inbin) return 1;
    inbin.read(reinterpret_cast<char*>(&p_read), sizeof(Point));
    std::cout << "Point1: (" << p_read.x << ", " << p_read.y << ")\n";
    inbin.read(reinterpret_cast<char*>(&p_read), sizeof(Point));
    std::cout << "Point2: (" << p_read.x << ", " << p_read.y << ")\n";
    inbin.close();
    return 0;
}

运行:

6、重要提示

  • 文件路径: 可以使用相对路径或绝对路径。相对路径是相对于程序运行时的当前工作目录。
  • 资源管理: 确保文件在不再需要时被关闭。利用 RAII (Resource Acquisition Is Initialization) 原则,让流对象的析构函数自动关闭文件是最安全的方式。
  • 二进制模式: 处理非文本数据(如图像、结构体)时,必须 使用 std::ios::binary 模式,否则可能发生意外的字符转换(如换行符 \n 在某些系统上可能被转换为 \r\n)。
  • 错误检查: 文件操作失败很常见(如文件不存在、权限不足、磁盘满)。务必在关键操作后进行错误检查。

掌握这些核心概念和操作,就能在 C++ 程序中有效地进行文件读写。

二、示例

以下是一个使用C++进行文件操作的示例代码,包含文件写入和读取的基本操作:

cpp 复制代码
#include <iostream>
#include <fstream>
#include <string>

int main() {
    // 文件写入操作
    std::ofstream outFile("example.txt"); // 创建输出文件流
    if (outFile.is_open()) {
        outFile << "Hello, File I/O!\n";
        outFile << "This is a sample text.\n";
        outFile << "3.1415926535\n";      // 写入数字
        outFile.close();
        std::cout << "数据写入成功!" << std::endl;
    } else {
        std::cerr << "无法打开文件进行写入!" << std::endl;
    }

    // 文件读取操作
    std::ifstream inFile("example.txt");   // 创建输入文件流
    std::string line;
    
    if (inFile.is_open()) {
        std::cout << "\n文件内容:" << std::endl;
        while (std::getline(inFile, line)) {
            std::cout << line << std::endl;
        }
        inFile.close();
    } else {
        std::cerr << "无法打开文件进行读取!" << std::endl;
    }

    // 追加模式写入
    std::ofstream appFile("example.txt", std::ios::app);
    if (appFile.is_open()) {
        appFile << "--- 追加内容 ---\n";
        appFile.close();
        std::cout << "\n追加内容成功!" << std::endl;
    }

    return 0;
}

代码说明:

  1. 文件写入

    • 使用 std::ofstream 创建输出文件流
    • is_open() 检查文件是否成功打开
    • 使用 << 运算符写入文本内容
    • 操作完成后调用 close() 关闭文件
  2. 文件读取

    • 使用 std::ifstream 创建输入文件流
    • std::getline() 逐行读取内容
    • 将读取内容输出到控制台
  3. 追加模式

    • 通过 std::ios::app 标志以追加模式打开文件
    • 新内容将添加到文件末尾而不覆盖原有内容

运行结果:

复制代码
数据写入成功!

文件内容:
Hello, File I/O!
This is a sample text.
3.1415926535

追加内容成功!


注意事项:

  1. 文件路径可以是相对路径(如示例)或绝对路径
  2. 操作前需确保有文件读写权限
  3. 使用 try-catch 可增强异常处理能力
  4. 对于二进制文件操作,需使用 std::ios::binary 模式
相关推荐
让学习成为一种生活方式2 小时前
如何根据过滤的pep序列进一步过滤gff3文件--python015
开发语言·人工智能·python
im_AMBER2 小时前
Leetcode 90 最佳观光组合
数据结构·c++·笔记·学习·算法·leetcode
heartbeat..2 小时前
Java NIO 详解(Channel+Buffer+Selector)
java·开发语言·文件·nio
云栖梦泽2 小时前
易语言开发者的知识沉淀与生态传承:从“用会”到“传好”
开发语言
2401_837088502 小时前
Hot 146 LRU Cache 实现详解
java·开发语言
Trouvaille ~2 小时前
【C++篇】智能指针详解(一):从问题到解决方案
开发语言·c++·c++11·类和对象·智能指针·raii
古城小栈2 小时前
Rust语言:优势解析与擅长领域深度探索
开发语言·后端·rust
superman超哥2 小时前
Rust Cargo.toml 配置文件详解:项目管理的核心枢纽
开发语言·后端·rust·rust cargo.toml·cargo.toml配置文件
玄同7652 小时前
面向对象编程 vs 其他编程范式:LLM 开发该选哪种?
大数据·开发语言·前端·人工智能·python·自然语言处理·知识图谱