用itertools.islice可流式按行分割大文件避免OOM,每次取n行;按字节分割需seek找换行符确保行完整,避免编码错误。

按行数分割文件:用 itertools.islice 避免内存爆炸
大文件一读就 OOM?别直接 readlines()。Python 的 open() 返回的是可迭代对象,配合 itertools.islice 可以流式切片,一行都不多占内存。
- 每次只取
n行:用islice(f, n),不是f.readlines()[:n](后者会把整个文件读进内存) - 注意
islice消耗迭代器位置,下一轮得重新打开文件或重置指针(推荐重开) - 如果文件是 GB 级、每行很短(如日志),按行切比按字节更安全——避免切在中间行里
from itertools import islice
<p>def split_by_lines(filepath, lines_per_file=10000):
with open(filepath) as f:
file_idx = 0
while True:
chunk = list(islice(f, lines_per_file))
if not chunk:
break
with open(f"{filepath}.part{file_idx}", "w") as out:
out.writelines(chunk)
file_idx += 1按字节大小分割:用 os.stat 和 seek 控制精度
按大小拆分看似简单,但容易切坏文本编码或截断某一行——尤其 UTF-8 中一个汉字可能占 2~4 字节,seek(n) 跳到中间会报 UnicodeDecodeError。
- 先用
os.stat(filepath).st_size获取总大小,再循环seek()+read(1)向后找换行符,确保每份以完整行为界 - 不要用
read(n_bytes)直接截,它不认行边界 - 二进制模式(
"rb")下操作更可控,但写回时需注意编码转换
def split_by_size(filepath, max_bytes=10_000_000):
with open(filepath, "rb") as f:
file_idx = 0
while True:
start = f.tell()
f.seek(0, 2) # 到末尾
if start >= f.tell():
break
f.seek(start)
# 读 max_bytes 或直到换行
chunk = b""
while len(chunk) < max_bytes:
b = f.read(1)
if not b:
break
chunk += b
if b == b"\n":
break
with open(f"{filepath}.part{file_idx}", "wb") as out:
out.write(chunk)
file_idx += 1
split 命令 vs Python 脚本:什么情况该放弃 Python
Linux/macOS 下,split 是真快、真稳、真省心——它不解析编码,不建对象,纯字节流切分,GB 文件几秒完事。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- 只要不介意文件名是
xaa、xab这种,且目标环境有 shell,优先跑:split -l 10000 big.log log_(按行)或split -b 10M big.bin bin_(按字节) - Windows 用户可用
gsplit(通过 Git for Windows 或 WSL),别硬写 Python 模拟 - Python 仅在需要后续处理(比如每份加 header、过滤字段、发 HTTP)时才值得介入
编码和换行符:两个隐藏雷区
你看到的“一行”,Python 不一定认得——特别是跨平台或混合编码的文件。
立即学习“Python免费学习笔记(深入)”;
-
\r\n(Windows)和\n(Unix)都算行结束,但readline()能自动识别;手动找\n会漏掉\r\n场景 - 文件若含
gbk、utf-16等编码,用默认open()会解码失败;必须显式传encoding=,且所有分片保持一致 - 用
open(..., newline="")可禁用 universal newlines,避免意外转换——但多数时候你反而要依赖它
按行切的关键是别把整文件拉进内存;按大小切的关键是别在行中间砍;而最常被忽略的,其实是确认源文件到底用什么编码、换行符长什么样——没看清这两点,后面全白调。

















