← 返回题目列表

Python 文本文件和二进制文件有什么区别?encoding 和 newline 参数有什么作用?

高频 中等 第 8 / 27 题 更新于 2026/07/27
文本IO二进制IO编码换行

简化版

文本文件读写的是 str,Python 会按 encoding 做字节和字符串之间的转换;二进制文件读写的是 bytes,不做编码转换。newline 控制文本模式下换行符如何识别和写出,跨平台处理 CSV、协议文本时尤其重要。

详细版

文本 I/O 和二进制 I/O 的核心区别是“有没有解码/编码层”。

with open("a.txt", "r", encoding="utf-8") as f:
    text = f.read()        # str

with open("a.txt", "rb") as f:
    data = f.read()        # bytes

文本模式下:

  • 读文件:磁盘字节按照 encoding 解码成 str
  • 写文件:str 按照 encoding 编码成字节;
  • Python 可能对换行符做通用换行处理;
  • 如果编码不匹配,可能抛 UnicodeDecodeError 或产生乱码。

二进制模式下:

  • 读写对象是 bytes
  • 不进行字符编码处理;
  • 不进行文本换行转换;
  • 适合图片、压缩包、网络协议二进制包、加密数据等。

newline 参数常见用法:

open("data.txt", "r", encoding="utf-8", newline=None)  # 默认,通用换行
open("data.txt", "r", encoding="utf-8", newline="")    # 保留换行细节,常用于 csv
open("data.txt", "w", encoding="utf-8", newline="\n")  # 写出统一 LF

面试中可以说:文本模式关心字符语义,二进制模式关心原始字节;只要内容不是纯文本,就优先二进制。

完整版教学

一、文件在磁盘上本质都是字节

操作系统层面没有“真正的字符串文件”。磁盘保存的是一串字节,比如:

E4 BD A0 E5 A5 BD

如果按 UTF-8 解码,它是“你好”;如果按错误编码解释,就可能变成乱码。Python 文本模式帮我们做的就是这层转换。

所以文本 I/O 的关键问题不是“能不能读”,而是“按什么编码读”。默认编码受运行环境影响,在 Windows、Linux、容器、CI 中可能不同。工程里处理文本文件,尤其是中文内容,建议显式指定:

with open("note.txt", "r", encoding="utf-8") as f:
    content = f.read()

二、为什么二进制文件不能用文本模式随便读

二进制文件没有字符语义。图片、PDF、zip、音视频中的字节组合不一定是合法文本编码。

如果用文本模式读取:

with open("logo.png", "r", encoding="utf-8") as f:
    data = f.read()

可能直接出现 UnicodeDecodeError。即使没有报错,也可能因为换行转换导致数据变化。对二进制文件来说,一个字节变了,文件就可能损坏。

正确写法是:

with open("logo.png", "rb") as f:
    data = f.read()

三、encoding 解决的是字节和字符的映射

encoding 参数只在文本模式下有意义。常见编码包括 utf-8gbklatin-1 等。

读文件时编码不匹配:

with open("gbk_file.txt", "r", encoding="utf-8") as f:
    print(f.read())

如果文件实际是 GBK,按 UTF-8 读就可能失败。面试里可以补充 errors 参数:

open("bad.txt", "r", encoding="utf-8", errors="replace")

errors="replace" 会用替代字符处理无法解码的字节,适合“尽量读出来做排查”的场景,但不适合严肃数据处理,因为它会丢失精确信息。

四、newline 解决的是换行符差异

不同系统历史上使用过不同换行表示:

  • Unix/Linux/macOS 常用 \n
  • Windows 常用 \r\n
  • 老式 Mac 曾使用 \r

文本模式默认会启用通用换行识别。读文件时,常见换行可能被统一转换成 \n。这对普通文本很方便。

但 CSV 是典型例外。Python 的 csv 模块建议打开文件时使用 newline="",让 csv 模块自己处理换行。如果不这么做,在某些平台上写 CSV 可能出现空行或换行不符合预期。

import csv

with open("users.csv", "w", encoding="utf-8", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(["id", "name"])

五、怎么判断该用文本还是二进制

可以问自己一个问题:我操作的是“字符内容”还是“原始字节”?

  • 配置文件、日志、Markdown、JSON、CSV:通常是文本;
  • 图片、音频、视频、压缩包、加密数据:通常是二进制;
  • 网络响应体:如果已知编码并要解析文本,可以解码;如果要保存原始内容,用二进制。

很多 bug 都来自“看起来像文本,其实边界不清”。比如 HTTP 响应、第三方上传文件、用户导出的 CSV,最好明确编码和换行策略。

六、常见误区与追问

记忆钩子:磁盘上永远是字节;文本模式帮你把字节解码成字符串,二进制模式让你直接面对 bytes。编码错了,字符就会乱;模式错了,数据可能被改。

  • 误区:文本文件和二进制文件在磁盘上本质不同。 磁盘上都是字节,区别在于程序是否按某种编码把字节解释为字符。
  • 追问:为什么图片、压缩包不能用文本模式处理? 文本模式会尝试解码并可能做换行转换,二进制数据不一定是合法文本,强行处理可能报错或破坏内容。
  • 误区:不写 encoding 也没问题。 默认编码依赖运行环境,跨机器可能不同;处理文本文件尤其是中文内容时应显式写 encoding="utf-8" 或实际编码。
  • 追问:errors="ignore" 是否推荐? 它会静默丢掉无法解码的字节,可能掩盖数据损坏;排查问题时更适合先用严格模式或 replace 看见异常字符。
  • 误区:所有系统换行符都是 \n Windows 文本文件常见 \r\n,Unix 常见 \n;文本模式可做通用换行处理,但 CSV 等格式有时要把 newline 控制权交给库。
  • 追问:为什么 len("中".encode("utf-8")) 不是 1? 字符数和字节数不同,中文字符在 UTF-8 中通常占 3 个字节;这也是文本随机 seek 比二进制更复杂的原因。

七、加强记忆

文本模式面对的是 str,核心是编码和换行;二进制模式面对的是 bytes,核心是保持原始字节不变。读中文文本要显式指定 encoding,处理 CSV 要留意 newline="",处理图片压缩包等非文本内容要坚定使用 rb / wb