Python写入文件最优方式:三种常见实现写法的优缺点对比
结论先行
三种写法中第三种写法综合表现最优,第一种适合小文件合并场景,第二种综合缺陷最多不推荐,具体优缺点和优化实践如下:
各写法优缺点分析
写法1:全量读入内存后一次性写入
# 1 way whole_data = "" for file_name in list_of_files: r_file = open(file_name, 'r') whole_data += r_file.read() r_file.close() with open("destination_file.txt", 'w') as w_file: w_file.write(whole_data)
- 优点:
- 目标文件仅打开关闭1次,IO操作次数少
- 写入是一次性操作,不会出现中间写入失败导致目标文件内容残缺的情况(要么全写完要么没写)
- 缺点:
- 内存占用极高:所有源文件的内容都会临时存在内存的
whole_data字符串里,如果源文件总大小超过可用内存,会直接触发内存溢出错误 - 字符串拼接效率低:Python中字符串是不可变对象,
whole_data += r_file.read()每次都会生成新的字符串对象,文件多或者体积大的时候性能损耗非常明显 - 读取文件没有用上下文管理器,中途如果读文件报错会导致文件句柄泄漏
- 内存占用极高:所有源文件的内容都会临时存在内存的
写法2:逐文件追加写入
# 2 way for file_name in list_of_files: r_file = open(file_name, 'r') with open("destination_file.txt", 'a') as w_file: w_file.write(r_file.read()) r_file.close()
- 优点:
- 不会占用大量内存,每次只存单个文件的内容
- 缺点:
- 目标文件打开关闭次数等于源文件数量,大量小文件场景下会产生非常多不必要的IO开销,性能极差
- 读取文件同样没用到上下文管理器,有句柄泄漏风险
- 追加写入过程中如果某一步报错,会导致目标文件只写入了部分内容,数据一致性差
写法3:目标文件一次打开,逐文件写入
# separate open/colse for write w_file = open("destination_file.txt", 'w') for file_name in list_of_files: with open(file_name, 'r') as r_file: w_file.write(r_file.read()) w_file.close()
- 优点:
- 目标文件仅打开关闭1次,IO开销低
- 每次只加载单个文件的内容到内存,内存占用低,大文件场景也不会触发内存溢出
- 读取源文件用到了上下文管理器,不会出现读文件的句柄泄漏问题
- 缺点:
- 写入过程中报错的话还是会出现目标文件内容残缺的问题
- 目标文件没有用上下文管理器,写入中途报错会导致目标文件句柄泄漏
更优的文件操作实践
在写法3的基础上做以下优化,可覆盖绝大多数场景:
- 读写全用上下文管理器,完全避免句柄泄漏
- 如果需要保证数据一致性,先写入临时文件,全部写完再重命名覆盖目标文件,避免中间失败产生脏文件
- 大文件场景下可以按块读写,进一步降低内存占用
优化后代码示例
# 常规小文件合并场景最优写法 with open("destination_file.txt", 'w') as w_file: for file_name in list_of_files: with open(file_name, 'r') as r_file: w_file.write(r_file.read()) # 大文件/需要保证数据一致性的场景 import os temp_file = "destination_file.txt.tmp" try: with open(temp_file, 'w') as w_file: for file_name in list_of_files: # 按4K块读写,内存占用稳定在KB级,不受文件大小限制 with open(file_name, 'r') as r_file: while chunk := r_file.read(4096): w_file.write(chunk) # 全部写完再替换原文件,原子操作保证数据一致性 os.replace(temp_file, "destination_file.txt") except Exception as e: # 出错删除临时文件,避免遗留垃圾文件 if os.path.exists(temp_file): os.remove(temp_file) raise e
内容的提问来源于stack exchange,提问作者Marcin Ziajkowski
相关产品推荐
相关产品推荐

