C++标准库:文件流类

在 C++ 标准库中,文件流类 (定义在 <fstream> 头文件中)用于实现对文件的输入输出(I/O)操作,允许程序读写磁盘文件。它们继承自标准 I/O 流类(如 std::istreamstd::ostream),因此支持与 cin/cout 类似的操作方式(如 >><< 运算符、getline 等)。

一、核心文件流类

根据操作方向(读/写)和功能,文件流类主要分为以下三类:

类名 继承关系 功能描述 典型用途
std::ifstream 继承自 std::istream 输入文件流:仅用于从文件读取数据 打开文本/二进制文件并读取内容
std::ofstream 继承自 std::ostream 输出文件流:仅用于向文件写入数据 创建/覆盖文件并写入内容
std::fstream 继承自 std::iostream 双向文件流:既可读又可写 需要同时读写同一文件的场景

二、文件打开与关闭

使用文件流类操作文件的基本流程是:创建流对象 → 打开文件 → 读写操作 → 关闭文件

1. 打开文件的两种方式
  • 通过构造函数打开:创建流对象时直接指定文件名和打开模式。
  • 通过 open() 成员函数打开 :先创建流对象,再调用 open() 打开文件。

两种方式都需要指定 打开模式 (控制文件的读写权限、是否覆盖等),常用模式定义在 <ios> 头文件中(可通过 | 组合):

打开模式标志 含义
std::ios::in 以"读"模式打开文件(ifstream 默认)
std::ios::out 以"写"模式打开文件(ofstream 默认)
std::ios::app 以"追加"模式打开:写入数据追加到文件末尾
std::ios::trunc 打开文件时清空原有内容(ofstream 默认)
std::ios::binary 以"二进制模式"打开(默认是文本模式)
std::ios::ate 打开文件后定位到文件末尾
2. 关闭文件

文件操作完成后需调用 close() 成员函数关闭文件,释放文件资源(流对象销毁时会自动调用 close(),但手动关闭更规范)。

三、常用操作示例

1. std::ofstream:写入文件

用于创建文件并写入内容,默认模式是 ios::out | ios::trunc(覆盖原有内容)。

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

int main() {
    // 方式1:通过构造函数打开文件(默认覆盖模式)
    std::ofstream ofs("output.txt");  // 若文件不存在则创建,存在则清空

    if (!ofs.is_open()) {  // 检查文件是否成功打开
        // 打开失败(如权限不足、路径不存在)
        return 1;
    }

    // 写入数据(支持 << 运算符,与 cout 用法一致)
    ofs << "Hello, File!" << std::endl;
    ofs << "This is a test." << std::endl;
    int num = 123;
    ofs << "Number: " << num << std::endl;

    // 方式2:追加模式写入(需指定 ios::app)
    std::ofstream ofs_app("output.txt", std::ios::app);
    ofs_app << "This line is appended." << std::endl;

    // 关闭文件
    ofs.close();
    ofs_app.close();
    return 0;
}

运行后 output.txt 内容:

复制代码
Hello, File!
This is a test.
Number: 123
This line is appended.
2. std::ifstream:读取文件

用于从现有文件读取内容,默认模式是 ios::in

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

int main() {
    // 打开文件(若文件不存在,打开失败)
    std::ifstream ifs("output.txt");
    if (!ifs.is_open()) {
        std::cerr << "Failed to open file!" << std::endl;
        return 1;
    }

    // 方法1:逐行读取(使用 getline)
    std::string line;
    std::cout << "----- 逐行读取 -----" << std::endl;
    while (std::getline(ifs, line)) {  // 读取到文件末尾时返回 false
        std::cout << line << std::endl;
    }

    // 重置流状态(因为上面的循环已读到文件末尾,需清除 eof 标志)
    ifs.clear();
    // 定位到文件开头(重新读取)
    ifs.seekg(0, std::ios::beg);  // seekg:移动读指针(g = get)

    // 方法2:逐个单词读取(使用 >> 运算符,忽略空格/换行)
    std::cout << "\n----- 逐单词读取 -----" << std::endl;
    std::string word;
    while (ifs >> word) {  // >> 自动跳过空白字符
        std::cout << word << " | ";
    }

    ifs.close();
    return 0;
}

运行输出:

复制代码
----- 逐行读取 -----
Hello, File!
This is a test.
Number: 123
This line is appended.

----- 逐单词读取 -----
Hello, | File! | This | is | a | test. | Number: | 123 | This | line | is | appended. | 
3. std::fstream:双向读写文件

需显式指定打开模式(如 ios::in | ios::out),支持同时读写。

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

int main() {
    // 打开文件:可读可写,若不存在则创建
    std::fstream fs("data.txt", std::ios::in | std::ios::out | std::ios::trunc);
    if (!fs.is_open()) {
        std::cerr << "Failed to open file!" << std::endl;
        return 1;
    }

    // 写入数据
    fs << "Apple\nBanana\nCherry" << std::endl;

    // 定位到文件开头(准备读取)
    fs.seekg(0, std::ios::beg);

    // 读取并修改第2行(示例:将 "Banana" 改为 "Blueberry")
    std::string line;
    int line_num = 0;
    std::string content;  // 暂存所有内容
    while (std::getline(fs, line)) {
        line_num++;
        if (line_num == 2) {
            line = "Blueberry";  // 修改第2行
        }
        content += line + "\n";
    }

    // 定位到文件开头(准备重新写入修改后的内容)
    fs.seekp(0, std::ios::beg);  // seekp:移动写指针(p = put)
    fs << content;  // 写入修改后的内容

    fs.close();
    return 0;
}

运行后 data.txt 内容:

复制代码
Apple
Blueberry
Cherry
4. 二进制文件操作

默认是文本模式(会对换行符等进行转换),指定 ios::binary 模式可读写二进制文件(如图片、音频)。读写时通常使用 read()write() 函数。

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

// 示例:二进制写入并读取结构体
struct Student {
    int id;
    char name[20];  // 固定长度,避免字符串指针问题
    float score;
};

int main() {
    // 二进制写入
    std::ofstream ofs("students.dat", std::ios::binary);
    Student s1 = {1001, "Alice", 95.5f};
    Student s2 = {1002, "Bob", 88.0f};
    ofs.write((const char*)&s1, sizeof(Student));  // 写入字节流
    ofs.write((const char*)&s2, sizeof(Student));
    ofs.close();

    // 二进制读取
    std::ifstream ifs("students.dat", std::ios::binary);
    Student s;
    while (ifs.read((char*)&s, sizeof(Student))) {  // 读取到缓冲区
        std::cout << "ID: " << s.id 
                  << ", Name: " << s.name 
                  << ", Score: " << s.score << std::endl;
    }
    ifs.close();
    return 0;
}

运行输出:

复制代码
ID: 1001, Name: Alice, Score: 95.5
ID: 1002, Name: Bob, Score: 88

四、关键操作与技巧

  1. 检查文件状态

    • is_open():判断文件是否成功打开。
    • eof():判断是否到达文件末尾(读取时常用)。
    • fail()/bad():判断是否发生错误(如读写失败、格式错误)。
    • clear():清除错误状态(如读取到末尾后重置,以便重新读写)。
  2. 文件指针定位

    • 读指针:seekg(pos, mode)mode 可选 ios::beg 开头、ios::cur 当前、ios::end 末尾)。
    • 写指针:seekp(pos, mode)(双向流中读/写指针可能独立,需分别定位)。
    • 获取当前指针位置:tellg()(读指针)、tellp()(写指针)。
  3. 避免中文乱码:文本模式下,文件编码需与程序输出编码一致(如均为 UTF-8 或 GBK),否则可能出现乱码。

五、注意事项

  • 路径处理 :打开文件时可指定绝对路径(如 C:/data/file.txt)或相对路径(相对于程序运行目录)。
  • 资源释放 :即使忘记调用 close(),流对象销毁时也会自动关闭文件,但手动关闭可避免资源泄漏(尤其在循环中频繁操作文件时)。
  • 权限问题:若打开文件失败,需检查路径是否存在、是否有读写权限(如操作系统对某些目录的保护)。

文件流类是 C++ 处理文件 I/O 的核心工具,无论是文本文件(如日志、配置)还是二进制文件(如媒体、数据),都能通过它们灵活操作,是实际开发中(如数据持久化、文件解析)的基础技能。

相关推荐
一拳一个呆瓜3 小时前
【MFC】对话框属性:X Pos(X位置),Y Pos(Y位置)
c++·mfc
siy23333 小时前
[c语言日记] 数组的一种死法和两种用法
c语言·开发语言·笔记·学习·链表
一拳一个呆瓜3 小时前
【MFC】对话框属性:Center(居中)
c++·mfc
njxiejing3 小时前
Python NumPy安装、导入与入门
开发语言·python·numpy
hai_qin3 小时前
十三,数据结构-树
数据结构·c++
Rhys..3 小时前
Python&Flask 使用 DBUtils 创建通用连接池
开发语言·python·mysql
土了个豆子的3 小时前
04.事件中心模块
开发语言·前端·visualstudio·单例模式·c#
@菜菜_达4 小时前
Lodash方法总结
开发语言·前端·javascript
GISer_Jing4 小时前
低代码拖拽实现与bpmn-js详解
开发语言·javascript·低代码