我使用AWSboto3
库,它返回一个urllib3.response.HTTPResponse
的实例。该响应是io.IOBase
的子类,因此表现为二进制文件。它的read()
方法返回bytes
个实例。在
现在,我需要从以这种方式接收的文件中解码csv
数据。我希望我的代码可以同时在py2
和py3
上工作,因此我使用backports.csv
,它依赖于io.IOBase
对象作为输入,而不是py2的file()
对象。在
第一个问题是HTTPResponse
为CSV文件生成bytes
数据,我有{
>>> import io
>>> from backports import csv # actually try..catch statement here
>>> from mymodule import get_file
>>> f = get_file() # returns instance of urllib3.HTTPResponse
>>> r = csv.reader(f)
>>> list(r)
Error: iterator should return strings, not bytes (did you open the file in text mode?)
我试图用io.TextIOWrapper
包装HTTPResponse
,但得到了错误'HTTPResponse' object has no attribute 'read1'
。这是预期的,因为TextIOWrapper
用于BufferedIOBase
对象,而不是{python2
的TextIOWrapper
的实现上,因为它总是期望底层对象具有read1
(source),而{read1
是否存在,并优雅地返回到read
(source)。在
然后我试图用io.BufferedReader
包装HTTPResponse
,然后用io.TextIOWrapper
包装。我得到了以下错误:
>>> f = get_file()
>>> br = io.BufferedReader(f)
>>> tw = io.TextIOWrapper(br)
>>> list(csv.reader(f))
ValueError: I/O operation on closed file.
经过一番调查发现,只有当文件不是以\n
结尾时才会发生错误。如果它以\n
结尾,那么问题就不会发生,一切都正常。在
在HTTPResponse
(source)中有一些关闭底层对象的附加逻辑,这似乎是导致问题的原因。在
问题是:如何将代码写入
HTTPResponse
的CSV文件,而不管它们是否以\n
结尾?在一种可能的解决方案是在TextIOWrapper
周围创建一个自定义包装器,当对象关闭时,read()
返回{
看起来这是} issue #1305 中描述。在
urllib3.HTTPResponse
和file
对象之间的接口不匹配。它在this ^{目前还没有修复程序,因此我使用了下面的包装器代码,看上去效果不错:
使用方法如下:
^{pr2}$类似的修复是由
urllib3
维护人员在bug报告评论中提出的,但这将是一个突破性的改变,因此目前情况可能不会改变,所以我不得不使用wrapper(或者做一些猴子补丁,这可能更糟)。在相关问题 更多 >
编程相关推荐