我有一个普通的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行的中间部分。我不明白。
答案 0 :(得分:5)
找到你的问题:
传递编码时,codecs.open
会返回StreamReaderWriter
,这实际上只是一个包装器(不是的子类;它&#39; sa&#34;由&#34;关系组成,而不是继承)StreamReader
和StreamWriter
。问题是:
StreamReaderWriter
提供正常的&#34; read
方法(也就是说,它需要一个size
参数,并且该方法就是这样)StreamReader.read
method,其中size
参数只是提示要读取的字节数,而不是限制; 第二个参数chars
是一个严格限制器,但StreamReaderWriter
从不传递该参数(它不接受它)size
提示,但未使用chars
上限时,如果StreamReader
已缓存数据,并且其大小足以匹配size
提示{{ 1}}盲目地返回缓冲区的内容,而不是基于StreamReader.read
提示以任何方式限制它(毕竟,只有size
强加最大返回大小) 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
],而是处理str
到unicode
或str
到str
编码,但这是一个非常有限的用例;大多数时候,您在bytes
和bytes
之间进行转换。您需要做的只是导入bytes
而不是str
,并将io
行更改为:
codecs
其余代码可以保持不变(并且可能会更快地启动)。
作为替代方案,您可以明确绕过codecs.open
以获取f = io.open("test.py", encoding="utf-8")
的{{1}}方法并直接传递限制参数,例如改变:
StreamReaderWriter
为:
StreamReader
我怀疑Python Bug #8260,其中包含read
和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
创建的文件对象上的混合,适用于此,正式,它已修复&#34; #34;,但是如果您阅读了注释,则修复程序尚未完成(并且可能无法在给定文档化API的情况下完成);任意奇怪的readline
和read
组合都可以打破它。
再次,只需使用codecs.open
;只要您使用的是Python 2.6或更高版本,它就可以使用,并且只是更好。