Python中open函数的r和rb模式有什么区别

阿麦
阿麦
发布时间:2026-11-05| 5人浏览过
原创

深入对比Python中open函数的r模式与rb模式的核心差异,涵盖返回值类型(str与bytes)、字符编码解码机制、跨平台换行符自动转换、文件指针跳转限制及具体业务场景选择指南。

Python中open函数的r和rb模式有什么区别
图 0:open() 函数中 'r' 与 'rb' 模式的快速对照概念图

在 Python 中使用内置的 open() 函数读取文件时,'r'(只读文本模式)和 'rb'(只读二进制模式)的核心区别在于数据处理层级:'r' 模式以字符(str)为单位,读取时会自动依据指定编码将磁盘字节解码为 Unicode 文本,并对跨平台换行符进行统一归一化转换;而 'rb' 模式以字节(bytes)为单位,直接原封不动地搬运磁盘上的原始二进制数据,不介入任何编码解码或字符转换。理解这两者的差异,是编写稳定文件读写代码、规避乱码和数据损坏的关键基础。

一、核心区别概览:文本流与字节流的处理链路

计算机磁盘物理存储的所有文件,本质上都是一段由 0 和 1 构成的原始字节流。操作系统并不知道也不关心文件里写的是一篇中文小说还是一张 PNG 图片。真正的分水岭发生在 Python 运行时如何读取这批字节:

  • 'r' 模式(Read Text):Python 在底层构建了一个 io.TextIOWrapper 文本流对象。从底层读取原始字节后,必须经过两个处理中间层:首先通过编码解码器(Decoder)转换成字符,随后通过通用换行符转换器(Universal Newlines)将不同操作系统的换行符折叠为标准的 。
  • 'rb' 模式(Read Binary):Python 构建的是 io.BufferedReader 二进制缓冲流对象。它绕过字符解码与换行符处理模块,直接将磁盘原始字节填充到内存中,提供纯粹的原生访问。
Python中open函数的r和rb模式有什么区别
图 1:磁盘数据进入 Python 内存的处理流水线对比

二、返回值类型与编码机制的差异

两种模式最直接的外在表现是 read() 方法返回的数据类型不同:

  • 使用 'r' 模式读取时,返回的是不可变的 str(字符串) 对象。
  • 使用 'rb' 模式读取时,返回的是不可变的 bytes(字节序列) 对象。

在 'r' 模式下,因为涉及字节到字符的转换,open() 函数允许且强烈要求传入 encoding 参数(例如 encoding='utf-8')。如果在 'r' 模式下省略 encoding,Python 会调用 locale.getpreferredencoding(False) 获取操作系统的默认编码。在 Windows 上这通常是 cp936(GBK),若读取 UTF-8 编码的文件便会抛出经典的 UnicodeDecodeError。

相反,在 'rb' 模式下,由于根本不执行解码操作,禁止传入 encoding 参数。若向 'rb' 模式传入该参数,Python 会立即报错。

# 示例代码:分别以 'r' 与 'rb' 模式读取同一文本文件
file_path = "example.txt"

# 1. 以 'r' 模式读取
with open(file_path, mode="r", encoding="utf-8") as f:
    text_data = f.read()
    print("模式 'r' 返回类型:", type(text_data))
    print("模式 'r' 返回内容:", repr(text_data))

# 2. 以 'rb' 模式读取
with open(file_path, mode="rb") as f:
    binary_data = f.read()
    print("模式 'rb' 返回类型:", type(binary_data))
    print("模式 'rb' 返回内容:", repr(binary_data))
示例运行输出
模式 'r' 返回类型: <class 'str'>
模式 'r' 返回内容: 'Python编程 '
模式 'rb' 返回类型: <class 'bytes'>
模式 'rb' 返回内容: b'Python编程 '
避坑提醒:错误传参引发的异常
若尝试执行 open("data.bin", mode="rb", encoding="utf-8"),Python 会在启动时直接抛出:
ValueError: binary mode doesn't take an encoding argument。
牢记:只有需要解码为字符串的文本模式才接受 encoding 与 errors 参数。

三、跨平台换行符转换机制(Universal Newlines)

不同操作系统在历史上定义了不同的文本换行符约定:

  • Windows:采用回车符与换行符组合 (十六进制 0x0D 0x0A,共 2 字节)。
  • Linux 与现代 macOS:采用单独的换行符 (十六进制 0x0A,1 字节)。
  • 早期 Mac(OS 9 以前):采用单独的回车符 (十六进制 0x0D,1 字节)。

为了让开发者无需针对不同平台编写繁琐的换行兼容逻辑,Python 在 'r' 文本模式下默认启用了通用换行符转换功能。无论文件是在 Windows 还是 Linux 下创建的,读取到 Python 内存中时,所有的 或 都会被默默转换为标准的单一 字符。

而在 'rb' 二进制模式下,换行符转换被完全禁用。磁盘上存储的如果是 0x0D 0x0A,读取到内存中的 bytes 就是 b' ',字节长度严格等于 2。

Python中open函数的r和rb模式有什么区别
图 2:跨平台换行符在 'r' 与 'rb' 模式下的转换机制

这种差异会导致一个非常经典的反直觉现象:在 Windows 下保存的文本,使用 'r' 模式读取得到的字符数(len(str)),会小于文件的实际字节大小(len(bytes))。因为每个 Windows 换行符的两个字节 被合成为了一个单字符 。

# 示例代码:验证换行符对读取长度的影响
windows_file = "crlf_demo.txt"

# 写入含有 Windows 换行符的数据
with open(windows_file, "wb") as f:
    f.write(b"Line1
Line2
")

# 以 'r' 模式读取
with open(windows_file, "r", encoding="utf-8") as f:
    content_text = f.read()
    print("文本模式长度 (len(str)):", len(content_text))
    print("文本模式内容:", repr(content_text))

# 以 'rb' 模式读取
with open(windows_file, "rb") as f:
    content_bytes = f.read()
    print("二进制模式长度 (len(bytes)):", len(content_bytes))
    print("二进制模式内容:", repr(content_bytes))
示例运行输出
文本模式长度 (len(str)): 12
文本模式内容: 'Line1 Line2 '
二进制模式长度 (len(bytes)): 14
二进制模式内容: b'Line1 Line2 '

四、文件指针定位(seek 与 tell)的行为限制

在处理大文件或需要随机读取时,经常需要配合使用 seek(offset, whence) 移动文件读取指针,以及使用 tell() 查看当前位置。两种模式在此处的规范极其严格:

  • 在 'rb' 模式下:偏移量代表绝对字节数。whence 参数可以为 0(从文件开头)、1(从当前位置)或 2(从文件末尾)。例如 seek(-10, 2) 表示跳到文件末尾倒数第 10 个字节处,行为完全符合低阶字节定位。
  • 在 'r' 模式下:由于 UTF-8 编码下中文占 3 个字节、换行符会被折叠,字符位置与底层字节偏移之间不存在简单的线性换算关系。因此在文本模式下,禁止随意指定非零字节偏移,且 whence 只能为 0(除非使用 seek(0, 2) 移到末尾)。若试图随意跳转(例如 seek(4)),一旦切在多字节字符的中间,下一次读取便会直接导致 UnicodeDecodeError。在文本模式下,合法的偏移量通常只能是先前通过 tell() 获取的不透明数值(Opaque Cookie)。

五、模式选择决策路径与标准操作步骤

在日常开发中,究竟应当选择 'r' 还是 'rb'?可以通过以下清晰的决策逻辑进行判断:

Python中open函数的r和rb模式有什么区别
图 3:文件读取模式选择与操作执行决策步骤

场景 1:读取并解析常规文本文件(选择 'r' 模式)

当文件内容是人类可阅读的自然语言文本、配置文件或由字符构成的结构化数据(如 .txt、.json、.csv、.md、.ini)时,应当选择 'r' 模式,并且必须显式传入 encoding="utf-8":

import json

# 正确示范:显式指定 utf-8 编码读取 JSON 文本
with open("config.json", mode="r", encoding="utf-8") as f:
    config = json.load(f)
    print("应用配置名称:", config.get("app_name"))

场景 2:处理多媒体、压缩包或序列化数据(必须选择 'rb' 模式)

当处理图片(PNG、JPEG)、音频(MP3、WAV)、视频(MP4)、压缩文件(ZIP、GZ)以及 Python 对象的持久化(Pickle、Protobuf)时,绝不能使用 'r' 模式。这些格式中包含大量随机分布的十六进制字节(包括 0x0D、0x0A、0xFF 等),如果用文本模式打开,换行符会被篡改、非文本字节解码失败,导致文件遭到破坏。

# 正确示范:以 'rb' 模式读取图片并检查头部魔数 (Magic Number)
with open("avatar.png", mode="rb") as f:
    header = f.read(8)
    # PNG 文件标准头部固定为 8 个字节
    is_png = (header == b"‰PNG

")
    print("是否为合法 PNG 文件:", is_png)

场景 3:计算文件哈希摘要或逐块传输(推荐选择 'rb' 模式)

即使是纯文本文件,如果当前任务是计算文件的 MD5/SHA256 校验和、进行网络断点续传或统计文件的精确字节大小,也应当采用 'rb' 模式。因为哈希计算要求的是磁盘上的原始物理字节,使用 'r' 模式会因为换行符归一化导致 Windows 与 Linux 下算出的哈希值不一致。

import hashlib

def calculate_file_sha256(filepath):
    sha256_hash = hashlib.sha256()
    # 使用 'rb' 模式分块读取,内存开销恒定且避免换行符篡改
    with open(filepath, "rb") as f:
        for chunk in iter(lambda: f.read(65536), b""):
            sha256_hash.update(chunk)
    return sha256_hash.hexdigest()

# 示例输出真实字节摘要
print("SHA256:", calculate_file_sha256("example.txt"))

六、常见误区与避坑指南

  • 误区 1:在文本模式下省略 encoding 参数
    许多初学者直接写 open("data.txt", "r"),在 macOS/Linux 开发测试一切正常,部署到客户的 Windows 服务器后立刻报 UnicodeDecodeError: 'gbk' codec can't decode byte...。无论何时,处理文本都要养成显式声明 encoding="utf-8" 的习惯。
  • 误区 2:尝试在 'rb' 模式读出的结果上调用字符串方法
    'rb' 读取得到的是 bytes,虽然部分方法名与 str 类似(如 split()、replace()),但其入参必须也是字节字面量(如 b"," 而非 ",")。若需进行复杂正则或字符串拼接,必须先通过 .decode("utf-8") 显式解码。
  • 误区 3:以为读写同一文件用不用 'b' 都无所谓
    在 Unix 系统上,历史上换行符本身就是 ,如果读写的是纯 ASCII 文件,'r' 与 'rb' 经常“巧合”地表现一致,这极具迷惑性。一旦跨平台到 Windows,或者遇到非 ASCII 字符(如中文、Emoji),隐患便会集中爆发。

七、核心特性对比与速查矩阵

为了便于日常查阅与记忆,下表及图示汇总了 'r' 与 'rb' 模式在各个维度的严格技术边界:

Python中open函数的r和rb模式有什么区别
图 4:'r' 与 'rb' 模式核心特性速查与技术总结矩阵
特性维度 'r' 模式(文本) 'rb' 模式(二进制)
返回类型 str(Unicode 字符) bytes(原始字节序列)
解码过程 自动解码(依赖 encoding) 不解码(原始物理数据直通)
换行符转换 与 默认自动转为 保持原始 0x0D、0x0A,不作任何修改
encoding 参数 允许且强烈推荐显式传入 禁止传入,传入抛出 ValueError
文件指针 seek 仅限 0 偏移或 tell() 记录的标记 支持从文件头/当前/文件尾的任意绝对字节跳转
适用对象 TXT、JSON、CSV、Markdown、Python源码等 图像、视频、音频、压缩包、哈希计算、网络传输

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。