【问题标题】:Reading a binary file in read mode Python 3 - passes on Windows, fails on Linux以读取模式 Python 3 读取二进制文件 - 在 Windows 上通过,在 Linux 上失败
【发布时间】:2023-11-29 11:57:01
【问题描述】:

我正在针对

执行这段代码

Windows 上的 Python

'3.6.8 |Anaconda, Inc.| (default, Feb 21 2019, 18:30:04) [MSC v.1916 64 bit (AMD64)]'

Linux 上的 Python

'3.6.6 (default, Mar 29 2019, 00:03:27) \n[GCC 4.8.5 20150623 (Red Hat 4.8.5-36)]'

代码使用wb 模式将一些字节写入文件,然后将其作为r 纯文本读取。我知道我应该按字节读取 (rb),但我很好奇为什么它在 Windows 上传递时会在 Linux 上中断?

import os
import tempfile
temp_dir = tempfile.mkdtemp()
temp_file = os.path.join(temp_dir, 'write_file')

expected_bytes = bytearray([123, 3, 255, 0, 100])
with open(temp_file, 'wb') as fh:
    fh.write(expected_bytes)

with open(temp_file, 'r', newline='') as fh:
    actual = fh.read()

在 Linux 上引发异常:

Traceback (most recent call last):
  File "<input>", line 11, in <module>
  File "/home/.../lib64/python3.6/codecs.py", line 321, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 2: invalid start byte

获取默认系统编码(使用sys.getdefaultencoding())显示 'utf-8' 在两台机器上。

【问题讨论】:

  • 可能是因为在 Windows 系统上读取时使用的默认编码不是 utf-8,而是像 latin-1 这样的编码,其中所有字节都对应一个有效字符。
  • 嗯,我刚刚检查了sys.getdefaultencoding(),两台机器上都是utf-8...
  • 来自open 的文档:'默认编码取决于平台(无论 locale.getpreferredencoding() 返回什么)' - 这个返回什么?
  • 试试locale.getpreferredencoding()
  • 还有:sys.getdefaultencoding() :返回 Unicode 实现使用的当前默认字符串编码的名称。

标签: python arrays python-3.x file binary


【解决方案1】:

当以文本模式打开文件时,使用'rt'('r' 和 't' 都是默认值),您从文件中读取的所有内容都会在运行中被透明解码并返回为str 对象,如Text I/O 中所述。

您可以在打开文件时强制使用编码,例如:

f = open("myfile.txt", "r", encoding="utf-8")

open 的文档中所述:

默认编码取决于平台(无论 locale.getpreferredencoding() 返回),但任何文本编码 可以使用 Python 支持的。请参阅编解码器模块以获取列表 支持的编码。

(注意sys.getdefaultencoding()是不相关的:它返回Unicode实现使用的当前默认字符串编码的名称)

正如您在 cmets 中所述,在您的系统上,locale.getpreferredencoding() 在 Windows 上提供“cp1252”,在 Linux 上提供“UTF-8”。

CP-1252 是单字节编码,其中每个字节对应一个字符。所以,无论你读什么文件,它所包含的数据都可以变成一个字符串。

UTF-8 但是,使用可变宽度编码,其中并非所有字节序列都是有效的并且代表一个字符。这就是为什么当某些字节无法解码时尝试在 Linux 系统上读取文件失败的原因。

【讨论】:

    【解决方案2】:

    如果您已将文件作为字节写出,则应将其作为字节读入。

    f = open("myfile.txt", "rb")
    

    如果您将其作为文本读入(使用"r""rt"),则会尝试将其解码为Unicode。默认使用什么编码取决于平台。但你显然根本不希望它被解码。

    【讨论】:

    • 感谢发帖。我确实明白将二进制文件作为纯文本阅读是没有意义的,我只是好奇表现出不同行为的环境之间有什么区别
    • 嗯,你有它。读取文本文件时,请明确说明您希望文件使用的编码。
    最近更新 更多