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

时间:2017-09-27 00:40:42

标签: python python-2.7 utf-8 readline codec

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

codecs

系统:

# 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"是什么意思?这就像第3行的中间部分。我不明白。

1 个答案:

答案 0 :(得分:5)

找到你的问题:

传递编码时,codecs.open会返回StreamReaderWriter,这实际上只是一个包装器(不是的子类;它&#39; sa&#34;由&#34;关系组成,而不是继承)StreamReaderStreamWriter。问题是:

  1. StreamReaderWriter提供正常的&#34; read方法(也就是说,它需要一个size参数,并且该方法就是这样)
  2. 它委托给内部StreamReader.read method,其中size参数只是提示要读取的字节数,而不是限制; 第二个参数chars是一个严格限制器,但StreamReaderWriter从不传递该参数(它不接受它)
  3. size提示,但未使用chars上限时,如果StreamReader已缓存数据,并且其大小足以匹配size提示{{ 1}}盲目地返回缓冲区的内容,而不是基于StreamReader.read提示以任何方式限制它(毕竟,只有size强加最大返回大小)
  4. API中chars的API以及StreamReader.read / size的含义是此处唯一记录的内容; chars返回codecs.open的事实不是契约性的,StreamReaderWriter包裹StreamReaderWriter的事实也是如此,我只是使用StreamReader&#39; s {{ 1}}魔术来阅读ipython模块的源代码来验证这种行为。但无论是否有文件记录,这都是它所做的事情(随意阅读??的源代码,它是所有Python级别的,所以它很容易)。

    最佳解决方案是切换到codecs,这在每种标准情况下都更快,更正确(StreamReaderWriter支持不在io.open之间转换的怪人编解码器[ Py2 codecs.open]和bytes [Py2 str],而是处理strunicodestrstr编码,但这是一个非常有限的用例;大多数时候,您在bytesbytes之间进行转换。您需要做的只是导入bytes而不是str,并将io行更改为:

    codecs

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

    作为替代方案,您可以明确绕过codecs.open以获取f = io.open("test.py", encoding="utf-8") 的{​​{1}}方法并直接传递限制参数,例如改变:

    StreamReaderWriter

    为:

    StreamReader

    我怀疑Python Bug #8260,其中包含readc = 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 创建的文件对象上的混合,适用于此,正式,它已修复&#34; #34;,但是如果您阅读了注释,则修复程序尚未完成(并且可能无法在给定文档化API的情况下完成);任意奇怪的readlineread组合都可以打破它。

    再次,只需使用codecs.open;只要您使用的是Python 2.6或更高版本,它就可以使用,并且只是更好。