Python:模式'wt'中的bz2和lzma不写BOM(而gzip会这样做)。为什么?

问题描述 投票:3回答:1

以下代码使用gzip,bz2和lzma编写压缩文本文件,然后读取并打印其二进制内容。

import bz2
import gzip
import lzma
import os


def test(encoding):
    print(encoding)
    for module in [gzip, bz2, lzma]:

        path = '/tmp/test.txt.%s' % module.__name__
        if os.path.exists(path):
            os.remove(path)

        with module.open(path, 'wt', encoding=encoding) as fout:
            fout.write('Ciao')

        with module.open(path, 'rb') as fin:
            print("%8s" % module.__name__, 'bytes:', fin.read())


test('utf-16')
print('')
test('utf-32')

输出是:

utf-16
    gzip bytes: b'\xff\xfeC\x00i\x00a\x00o\x00'
     bz2 bytes: b'C\x00i\x00a\x00o\x00'
    lzma bytes: b'C\x00i\x00a\x00o\x00'

utf-32
    gzip bytes: b'\xff\xfe\x00\x00C\x00\x00\x00i\x00\x00\x00a\x00\x00\x00o\x00\x00\x00'
     bz2 bytes: b'C\x00\x00\x00i\x00\x00\x00a\x00\x00\x00o\x00\x00\x00'
    lzma bytes: b'C\x00\x00\x00i\x00\x00\x00a\x00\x00\x00o\x00\x00\x00'

如您所见,bz2和lzma不写BOM(字节顺序标记),而gzip按预期方式执行。这意味着如果我尝试在文本模式下读取bz2 / lzma文件(例如bz2.open(path, 'rt', encoding='utf-16')),则会引发UnicodeError抱怨丢失的BOM。

这是为什么?这是一个错误吗?

python compression utf byte-order-mark
1个回答
0
投票

我在回答我自己的问题。简而言之:是的,它肯定是io.TextIOWrapper的C实现的一个错误。

当您以文本模式(压缩或未压缩)打开文件时,返回的是包装二进制文件读取器的io.TextIOWrapperio.TextIOWrapper_io扩展模块中用C实现。事实证明,还有io模块的Python实现,即_pyio模块。 _pyio.TextIOWrapper按预期工作,所以它绝对是C实现的错误。

以下代码演示了此问题:

import bz2
import io
import _pyio

def test(io_module, encoding='utf-16'):
    path = '/tmp/test.txt.bz2'

    with io_module.TextIOWrapper(bz2.open(path, 'w'), encoding=encoding) as fout:
        fout.write('Ciao')

    with bz2.open(path, 'rb') as fin:
        print("%5s" % io_module.__name__, 'bytes:', fin.read())


test(io)
test(_pyio)

打印:

   io bytes: b'C\x00i\x00a\x00o\x00'
_pyio bytes: b'\xff\xfeC\x00i\x00a\x00o\x00'
© www.soinside.com 2019 - 2024. All rights reserved.