rb模式绕过了编码解码、换行符转换、字符串对象构造、BOM检测等文本层开销;其返回bytes而非str,避免了逐行扫描、内存切片分配及频繁短生命周期对象创建,I/O调用更少、吞吐更高。

因为二进制读取跳过了所有文本层处理——不解析换行符、不转换编码、不拆分字符串,直接把字节块原样搬进内存。
rb 模式绕过了哪些开销?
Python 的 open(..., 'r')(文本模式)在底层会做三件事:read() 返回的是 str,而 open(..., 'rb') 返回的是 bytes。这意味着:
- 文本模式必须按系统或指定的
encoding解码每个字节序列,比如 UTF-8 中一个中文字符可能占 3 字节,解码器得边扫描边判断边界 - 逐行读取(
for line in f:)要反复查找\n或\r\n,每次定位都涉及内存扫描和切片分配 - 每行末尾的换行符会被剥离,还要额外构造一个新的
str对象 - 如果文件带 BOM(如
utf-8-sig),开头还得做一次前缀检测和截断
大文件下 rb.read() 和 for line in f 的性能差距在哪?
差距不是“一点点”,而是数量级差异。关键在于 I/O 调用次数和内存操作频率:
-
rb.read()通常一次系统调用就把整个文件(或大块)读入缓冲区,后续只是内存拷贝 -
for line in f:在内部其实是不断调用f.readline(),每次都要从缓冲区找下一个\n,找不到就触发下一次read()系统调用——小文件看不出,但 100MB 日志里平均一行几十字节时,会触发上百万次边界判断 - 实测:读取 200MB 纯文本日志,
rb.read()耗时约 0.15s;逐行迭代耗时常超 1.2s,且内存峰值高 3–4 倍(因频繁创建短生命周期str对象)
什么时候不能用 rb.read() 替代逐行读取?
不是所有场景都能“一读了之”,核心约束是内存和语义:
- 文件远大于可用内存(比如 10GB 文件配 4GB RAM),
rb.read()直接触发MemoryError - 你需要按逻辑行处理(如跳过注释、提取某列、流式清洗),
rb返回的是bytes,得自己用.split(b'\n')或io.BytesIO模拟行迭代,反而更麻烦 - 混合编码文件(如部分行 GBK、部分 UTF-8),二进制读取虽快,但后续解码会崩溃,不如文本模式配合
errors='ignore'或逐块解码 - 某些协议要求严格按行响应(如 HTTP chunked transfer),不能等全量读完
真正快的从来不是“用 rb”,而是“少做没必要的事”。如果你只是校验文件一致性、计算 hash、或批量写入另一个二进制文件,rb + read() 就是最简最优解;但一旦涉及内容理解,快慢就得让位于正确性——这时候花在解码和分割上的时间,不是浪费,是必要成本。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











