学而时习之:C++中的文件处理2

C++ 中的 I/O 重定向

在 C++ 中,输入和输出通过"流"(stream)完成。流就是字节序列。常见的流对象有:

  • cin:从键盘读取输入
  • cout:把输出显示到屏幕

每个流都带有一个"缓冲区"(buffer),用来临时存放数据,让输入输出更快。
"I/O 重定向" 就是改变程序"从哪儿读"或"写到哪儿"。例如,把本来输出到屏幕的内容写进文件。

使用 ios::rdbuf() 进行重定向

函数 ios::rdbuf() 可以把流重定向到别的源头或目的地,让程序读写文件,而不是默认的键盘和屏幕。

示例代码:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int main()
{
    
    ofstream file;      // 1. 创建一个输出文件流
    file.open("writeFile.txt");

    streambuf *cout_buf = cout.rdbuf();    // 2. 保存 cout 原来的缓冲区指针,以便后续恢复

    streambuf *file_buf = file.rdbuf();    // 3. 拿到文件流对应的缓冲区指针

    cout.rdbuf(file_buf); // 4. 把 cout 的缓冲区换成文件的缓冲区,实现重定向

    // 5. 此时用 cout 输出的内容会写进文件 writeFile.txt
    cout << "This line will be written to "  << "'writeFile.txt'";

    // 6. 手动刷新,确保数据真正写进文件
    cout.flush();

    // 7. 把 cout 的缓冲区恢复成默认(屏幕)
    cout.rdbuf(cout_buf);

    // 8. 这条信息会正常显示在控制台
    cout << "This line will be writtein to console";

    // 9. 关闭文件流
    file.close();

    return 0;
}

程序运行后屏幕实际只会看到:

arduino 复制代码
This line will be writtein to console

而文件 writeFile.txt 里会多出:

arduino 复制代码
This line will be written to 'writeFile.txt'

使用 freopen() 进行重定向

这是 C++ 里另一种实现 I/O 重定向的办法,但它其实是从 C 语言继承过来的。

语法:

cpp 复制代码
freopen(fileName, mode, stream);

参数说明:

  • fileName:要重定向到的文件路径。
  • mode:文件打开模式,例如只读 "r"、写入 "w" 等。
  • stream:要被重定向的标准流指针,如 stdoutstdinstderr

返回值:

成功时返回指向新文件流的指针;失败返回 NULL

示例代码:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int main()
{
    // 1. 把标准输出(stdout)重定向到文件 "output_freopen.txt",模式为写入("w")
    if (freopen("output_freopen.txt", "w", stdout) == NULL)
    {
        cerr << "重定向 stdout 失败!" << endl;
    }

    // 2. 此时用 cout 输出的内容都会写进文件,而不会出现在控制台
    cout << "This output will be written to 'output_freopen.txt'" << endl;
    cout << "Another line to the file.";

    return 0;
}

程序运行后屏幕不会显示任何内容, 但文件 output_freopen.txt 里会出现:

vbnet 复制代码
This output will be written to 'output_freopen.txt'
Another line to the file.

为什么需要 I/O 重定向

把标准输入输出"换道"后,程序能获得以下好处:

  1. 自动化:同一份输入数据可反复跑,无需手工敲键盘,批量测试、脚本处理必备。
  2. 数据管道:一个程序的输出直接当另一个程序的输入,命令行里轻松搭起流水线。
  3. 测试与调试:换文件就能换测试场景;把输出抓进文件,随时比对预期结果。
  4. 日志与监控:把正常输出或错误信息重定向到日志文件,方便排错、审计和长期监控。
  5. 控制台清爽:后台跑程序时屏幕保持干净,结果事后看文件即可。

ios::rdbuf() 与 freopen() 的区别

ios::rdbuf() freopen()
用于获取或更换 istream/ostream 的内部缓冲区指针。 把已存在的文件"绑"到标准流(stdin/stdout/stderr)上。
只改流对象内部缓冲区,文件描述符不变。 连文件描述符一起换掉,真正重定向到指定文件。
可对缓冲机制做细粒度控制(如切回原来缓冲区)。 仅完成"文件↔流"的映射,不直接操作缓冲区。
属于 C++ 风格的流库接口。 继承自 C 标准库,跨 C/C++ 通用。

C++ 文件流 API简单总结

C++ 文件流 API 一览(按"干什么"分类,只列标准库 <fstream> + <filesystem> 高频接口,C++17 及以上标⭐)

1. 打开/关闭/文件状态

目的 关键成员
构造函数即打开 std::ifstream/ofstream/fstream 带路径构造
事后打开 .open(path, mode)
关闭 .close()
是否打开成功 operator! / .fail() / .is_open()
文件是否存在⭐ std::filesystem::exists(path)
文件大小⭐ std::filesystem::file_size(path)

2. 读写定位

目的 关键成员
读位置 .tellg()
写位置 .tellp()
跳读 .seekg(offset, dir)
跳写 .seekp(offset, dir)
dir 枚举 std::ios::beg/cur/end

3. 按字符/行/块 读写

方式 关键调用
单字符 stream.get(c) / stream.put(c)
std::getline(stream, string)
整块 stream.read(buf, n) / stream.write(buf, n)
已读字节数 stream.gcount()

4. 格式化写入,读取

目的 用法
与控制台语法一致 直接用 读【>>】 , 写【 <<

5. 缓冲区底层控制

目的 关键调用
换缓冲区 stream.rdbuf(new_buf)
取当前缓冲区 stream.rdbuf()
手动刷盘 stream.flush()
与 std::cout 同步开关 std::ios::sync_with_stdio(bool)

6. 打开模式位(可组合)

含义
std::ios::in
std::ios::out 写(默认 truncate)
std::ios::app 追加
std::ios::ate 打开后指针置尾
std::ios::trunc 若已存在则截空
std::ios::binary 二进制模式

7. 错误与状态检测

状态函数 含义
.good() 一切正常
.eof() 读到 EOF
.fail() 格式/逻辑错误
.bad() 严重错误(设备故障)
.clear(flags=std::ios::goodbit) 手动清状态

8. 文件系统级操作⭐(<filesystem>

任务 调用
创建目录 std::filesystem::create_directory/parent_path
拷贝文件 std::filesystem::copy_file
改名/移动 std::filesystem::rename
删除 std::filesystem::remove/all
遍历目录 std::filesystem::directory_iterator
路径拼接 operator/std::filesystem::path::append
相关推荐
fakerth3 小时前
【OpenHarmony】设计模式模块详解
c++·单例模式·设计模式·openharmony
biter down3 小时前
C++ 解决海量数据 TopK 问题:小根堆高效解法
c++·算法
程芯带你刷C语言简单算法题3 小时前
Day28~实现strlen、strcpy、strncpy、strcat、strncat
c语言·c++·算法·c
一个不知名程序员www3 小时前
算法学习入门--- 树(C++)
c++·算法
Simon席玉4 小时前
C++的命名重整
开发语言·c++·华为·harmonyos·arkts
仰泳的熊猫4 小时前
1148 Werewolf - Simple Version
数据结构·c++·算法·pat考试
十五年专注C++开发4 小时前
同一线程有两个boost::asio::io_context可以吗?
c++·boost·asio·异步编程·io_context
xlq223225 小时前
26 avl树(下)
c++
郝学胜-神的一滴5 小时前
深入理解OpenGL VBO:原理、封装与性能优化
c++·程序人生·性能优化·图形渲染