直接用open()逐个读写最可靠,因shutil.copyfileobj仅支持两文件字节搬运、不处理编码差异与换行衔接,强行循环易因unicodedecodeerror中断或内容粘连。

直接用 open() 逐个读取再写入一个文件,是最可靠、可控性最强的方式。其他“一行命令”方案(比如 shutil.copyfileobj 或 shell 拼接)在跨平台、编码不一致或大文件场景下容易出错。
为什么不能直接用 shutil.copyfileobj 拼接多个文件?
shutil.copyfileobj 只接受两个文件对象(src 和 dst),不支持链式拼接;强行循环调用时,若源文件编码不统一,会因 UnicodeDecodeError 中断,且无法自动处理换行符衔接(比如前一个文件末尾没换行,后一个文件开头也没空行,就会粘连)。
- 它不关心文本内容,只做字节搬运 —— 编码错误、BOM、行尾差异全得你兜底
- 没有内置的“按顺序读取多个路径”的逻辑,需额外遍历
- 对超大文件虽支持
length参数缓冲,但拼接逻辑仍得手动组织
推荐做法:用 open() 控制编码和换行
显式指定 encoding='utf-8'(或根据实际调整),并在每次写入前判断是否需要补换行,确保“无缝”——即内容连贯、无多余空行、无乱码。
with open('output.txt', 'w', encoding='utf-8') as out_f:
for i, path in enumerate(['a.txt', 'b.txt', 'c.txt']):
with open(path, 'r', encoding='utf-8') as f:
content = f.read().rstrip('\n') # 去掉末尾换行,避免重复
if i > 0:
out_f.write('\n') # 文件间只加一个换行
out_f.write(content)
-
rstrip('\n')防止前一个文件自带换行导致空行;if i > 0确保第一个文件不前置换行 - 若某些文件是
gbk或带 BOM 的utf-8-sig,需单独用encoding='utf-8-sig'或encoding='gbk'打开 - 对特别大的单个文件,改用逐行读取:
for line in f:,避免内存爆掉
遇到 UnicodeDecodeError: 'utf-8' codec can't decode byte 怎么办?
说明至少有一个文件不是 UTF-8 编码。硬设 errors='ignore' 或 'replace' 会丢数据或引入 ,应先探测编码。
- 用
chardet.detect()快速试判(注意:小文件准确率高,大文件可采样前 10KB) - 更稳妥的是按常见编码列表依次尝试:
['utf-8', 'gbk', 'latin-1'],捕获异常后换下一个 - Windows 记事本保存的 ANSI 文件,大概率是
gbk(中文 Windows)或cp1252(英文 Windows)
真正麻烦的不是拼接动作本身,而是混合编码 + 不规范换行 + 隐式 BOM —— 这些细节不提前检查,合并完才发现某段文字变乱码或两行挤成一行,返工成本远高于一开始多写几行探测逻辑。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











