小编典典

codecs.open(utf-8)无法读取纯ASCII文件

python

我有一个普通的ASCII文件。当我尝试使用打开它时codecs.open(...,"utf-8"),我无法读取单个字符。ASCII是UTF-8的子集,那么为什么不能codecs在UTF-8模式下打开这样的文件?

# test.py

import codecs

f = codecs.open("test.py", "r", "utf-8")

# ASCII is supposed to be a subset of UTF-8:
# http://www.fileformat.info/info/unicode/utf8.htm

assert len(f.read(1)) == 1 # OK
f.readline()
c = f.read(1)
print len(c)
print "'%s'" % c
assert len(c) == 1 # fails

# max% p test.py
# 63
# '
# import codecs
#
# f = codecs.open("test.py", "r", "utf-8")
#
# # ASC'
# Traceback (most recent call last):
#   File "test.py", line 15, in <module>
#     assert len(c) == 1 # fails
# AssertionError
# max%

系统:

Linux max 4.4.0-89-generic #112~14.04.1-Ubuntu SMP Tue Aug 1 22:08:32 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

当然,它可以正常使用open。如果我删除该"utf-8"选项,它也可以工作。还有什么63意思?就像第三行的中间。我不明白


阅读 136

收藏
2021-01-20

共1个答案

小编典典

发现您的问题:

通过编码后,codecs.open返回StreamReaderWriter,实际上只是一个包装器( 不是
其子类;它是“由……组成”的关系,而不是继承)StreamReaderStreamWriter。问题是:

  1. StreamReaderWriter提供一个“普通”read方法(即,它带有一个size参数就可以了)
  2. 它委托给内部StreamReader.read方法,其中size参数仅是要读取的字节数的提示,而不是限制。在 第二个 参数,chars是一个严格的限制,但StreamReaderWriter从来没有经过这样的说法沿(不接受)
  3. 当有size提示但没有使用限制时chars,如果StreamReader已缓冲数据,并且足够大以匹配size提示StreamReader.read盲目地返回缓冲区的内容,而不是根据size提示以任何方式对其进行限制(毕竟,仅chars施加 最大 返回值)

APIStreamReader.read以及API的size/的含义chars是此处唯一记录的内容;codecs.open返回的事实StreamReaderWriter不是契约性的,也不是StreamReaderWriter包装的事实StreamReader,我只是使用ipython??魔术来读取codecs模块的源代码来验证此行为。但是,无论是否有记录,这就是它的作用(可以随意阅读的源代码StreamReaderWriter,它全部是Python级别的,因此很容易)。

最好的解决办法是切换到io.open,这是在每一个标准的情况下,更快,更正确的是(codecs.open支持怪人编解码器不转换之间bytes[的Py2
str]和str[的Py2
unicode],而是手柄strstrbytesbytes编码,但是这是一个令人难以置信用例有限;大多数情况下,您是在bytes和之间进行转换str。您需要做的只是importio而不是codecs,并将codecs.open行更改为:

f = io.open("test.py", encoding="utf-8")

您的其余代码可以保持不变(并且可能会以更快的速度启动)。

作为替代方案,您可以显式地绕过StreamReaderWriter以获得StreamReaderread方法并直接传递限制参数,例如change:

c = f.read(1)

至:

# Pass second, character limiting argument after size hint
c = f.reader.read(6, 1)  # 6 is sort of arbitrary; should ensure a full char read in one go

我怀疑PythonBug#8260(涉及混合readlinereadcodecs.open创建的文件对象上)在此处正式应用,即为“已修复”,但如果您阅读注释,则修复未完成(鉴于所记录的文档,可能无法完成API);随意的怪异组合,read并且readline将能够打破它。

同样,只需使用io.open; 只要您使用的是Python 2.6或更高版本,它就可以使用,并且会更好。

2021-01-20