为了避免Python中的MemoryError,我试图读取块。一直在寻找半天如何从RestResponse读取块,但无济于事。
源是一个类似文件的对象,使用Dropbox SDK for python。
这是我的尝试:
import dropbox
from filechunkio import FileChunkIO
import math
file_and_metadata = dropbox_client.metadata(path)
hq_file = dropbox_client.get_file(file_and_metadata['path'])
source_size = file_and_metadata['bytes']
chunk_size = 4194304
chunk_count = int(math.ceil(source_size / chunk_size))
for i in range(chunk_count + 1):
offset = chunk_size * i
bytes = min(chunk_size, source_size - offset)
with FileChunkIO(hq_file, 'r', offset=offset,
bytes=bytes) as fp:
with open('tmp/testtest123.mp4', 'wb') as f:
f.write(fp)
f.flush()
这会导致“TypeError:强制转换为Unicode:需要字符串或缓冲区,找到RESTResponse”
非常感谢任何线索或解决方案。
答案 0 :(得分:0)
在不了解FileChunkIO
的情况下,甚至不知道代码在哪里引发异常,很难确定,但我的猜测是它需要一个真正的文件类对象。或者它可能会做一些愚蠢的事情,比如检查类型,以便它可以决定你是在寻找一个字符串还是一块文件。
无论如何,根据文档,RESTResponse
不是一个完整的文件对象,但它实现了read
和close
。你可以轻松地实现read
实现read
的东西,而不需要任何花哨的包装器。当你到达EOF时,类文件对象的b''
方法保证返回read
,并且返回的字节数比你要求的少,所以你不需要猜测你需要多少次chunk_size = 4194304
with open('tmp/testtest123.mp4', 'wb') as f:
while True:
buf = hq_file.read(chunk_size)
if not buf:
break
f.write(buf)
并在最后做一个简短的阅读。就这样做:
open
(注意我将chunk_size = 4194304
chunks = iter(lambda: hq_file.read(chunk_size), '')
with open('tmp/testtest123.mp4', 'wb') as f:
f.writelines(chunks)
移到了循环之外。否则,对于每个chunk,你将打开并清空文件,然后写下一个chunk,所以最后你会最后只有最后一个。)
如果你想要一个分块包装器,那么有一个非常好的内置函数iter
可以为你做到:
''
请注意,如果您将b''
更改为writelines
,但完全相同的代码在Python 3.x中有效,但这会破坏Python 2.5。
这可能有点滥用partial(hq_file.read, chunk_size)
,因为我们正在编写一个实际上不是行的字符串的迭代。如果您不喜欢它,那么显式循环就会变得简单而简洁。
我通常把它写成lambda: hq_file.read(chunk_size_
而不是{{1}},但这确实是一个偏好问题;阅读partial
上的文档,你应该能够理解为什么它们最终具有相同的效果,并决定你喜欢哪一个。