发现你的问题:
当传递编码时,codecs.open
返回一个StreamReaderWriter
,这实际上只是 (not的子类;这是一种“组成”关系,而不是继承)StreamReader
and StreamWriter
。问题是:
-
StreamReaderWriter
提供“正常”read
方法(也就是说,它需要一个size
参数就是这样)
- 它委托给内部StreamReader.read method,其中
size
argument 只是关于要读取的字节数的提示,而不是限制;这second争论,chars
,是一个严格的限制器,但是StreamReaderWriter
从不传递该论点(它不接受它)
- When
size
暗示,但不限制使用chars
, if StreamReader
有缓冲数据,并且它足够大以匹配size
hint StreamReader.read
盲目地返回缓冲区的内容,而不是根据缓冲区以任何方式限制它size
提示(毕竟只是chars
强加一个maximum返回尺寸)
的 APIStreamReader.read
和的意义size
/chars
因为 API 是这里唯一有记录的东西;事实是codecs.open
回报StreamReaderWriter
不是契约性的,也不是事实StreamReaderWriter
wraps StreamReader
,我刚刚用过ipython
's ??
魔法阅读源代码codecs
模块来验证此行为。但无论是否有记录,这就是它正在做的事情(请随意阅读源代码StreamReaderWriter
,都是Python级别的,所以很简单)。
最好的解决方案是切换到io.open
,在每个标准情况下都更快、更正确(codecs.open
支持不相互转换的怪异编解码器bytes
[Py2 str
] and str
[Py2 unicode
],而是处理str
to str
or bytes
to bytes
编码,但这是一个极其有限的用例;大多数时候,你在之间转换bytes
and str
)。您所需要做的就是导入io
代替codecs
,并更改codecs.open
线路至:
f = io.open("test.py", encoding="utf-8")
其余代码可以保持不变(并且启动时可能会运行得更快)。
作为替代方案,您可以显式绕过StreamReaderWriter
得到StreamReader
's read
方法并直接传递限制参数,例如改变:
c = f.read(1)
to:
# 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
我猜测Python 错误 #8260,其中涵盖了混合readline
and read
on codecs.open
创建的文件对象,适用于此处,正式地,它是“已修复”,但如果您阅读注释,则修复尚未完成(鉴于已记录的 API,可能无法完成);任意奇怪的组合read
and readline
就能打破它。
再次,只需使用io.open
;只要您使用的是 Python 2.6 或更高版本,它就可用,而且效果明显更好。