正确做法是只打开一次输出文件并保持句柄有效,在循环外用std::ofstream out("output.txt", std::ios::app)打开,每个输入文件用独立std::ifstream读取后立即关闭,写入前检查is_open(),必要时手动添加分隔符。

用 std::ofstream 以 std::ios::app 模式打开文件就能追加,但别在循环里反复开闭
合并多个 TXT 文件时,很多人习惯每读一个文件就用 std::ofstream 以 std::ios::app 模式打开输出文件一次。这看似安全,实则低效且易出错——每次开闭文件都触发系统调用,还可能因权限、路径或编码问题中断;更隐蔽的是,若某个输入文件读取失败(比如空文件、权限不足),你可能只得到部分结果却无提示。
正确做法是:只打开一次输出文件,保持句柄有效,在循环中持续写入。
- 输出文件用
std::ofstream out("output.txt", std::ios::app)打开一次,放在循环外 - 每个输入文件用独立的
std::ifstream读取,读完即关,互不影响 - 写入前检查
out.is_open()和in.is_open(),避免静默失败 - 若需分隔不同源文件内容,手动写入换行或分隔线(
out )
读取时别用 while (!in.eof()),它会导致最后一行重复或漏读
while (!in.eof()) 是 C++ 文件读取中最常见的陷阱之一。它不检测读操作是否成功,而只检查流是否已到末尾——但“末尾”状态通常在一次失败读取后才置位,所以循环体常会多执行一次,把上一轮的有效数据再处理一遍。
真正可靠的模式是把读取动作本身作为条件判断:
- 按行读取:用
while (std::getline(in, line)) - 按词读取:用
while (in >> word) - 读取原始字节:用
in.read(buf, size)后检查in.gcount()
这样能确保每次进入循环体前,数据已成功载入。
Windows 下中文路径或内容乱码?优先用窄字符 + 系统本地编码,别硬上 UTF-8
C++ 标准库的 std::ifstream/std::ofstream 在 Windows 上默认使用系统 ANSI 编码(如 GBK),不是 UTF-8。如果你的 TXT 文件是记事本默认保存的“ANSI”格式(实际是 GBK),而你强行用 UTF-8 字符串去读,就会乱码;反之,若文件是 UTF-8 无 BOM,又没指定 codecvt,也会崩。
简单场景下最稳的做法是:保持窄字符串(std::string),不显式设置 locale,让流走系统默认编码。
- 不要对
std::ifstream调用imbue(std::locale("zh-CN"))—— 它在多数编译器上不可靠 - 避免用
std::u8string或std::wstring处理路径,除非你明确用std::wifstream并配合 WinAPI - 路径含中文?确保编译器和终端支持当前代码页(Visual Studio 默认是 GBK;MinGW/Clang 可能需加
-fexec-charset=GBK)
合并大文件时内存不爆但速度慢?关键在缓冲区和同步
逐行读写小文件没问题,但合并几个百 MB 的日志文件时,你会发现速度远低于预期。瓶颈往往不在磁盘,而在频繁的 I/O 刷新和同步等待。
- 关闭
std::cin/std::cout与 C 标准流的同步:std::ios::sync_with_stdio(false),这能提速 2–3 倍 - 给
std::ofstream设置更大缓冲区:out.rdbuf()->pubsetbuf(buffer, bufsize)(注意:必须在 open 前调用) - 避免每行都
out —— 它强制刷新;改用"\n",最后统一out.flush() - 如果只是拼接,不用解析内容,可考虑用
in.read()+out.write()批量搬运二进制块(跳过换行符转换)
最常被忽略的一点:输出文件是否已存在、是否可写、是否有同名正在被其他程序占用——这些错误不会抛异常,is_open() 返回 false,但很多人没检查就直接写,结果什么也没发生。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











