Python3.6的Zipfile模块:为Odoo写入字节而不是文件

Python3.6的Zipfile模块:为Odoo写入字节而不是文件,python,odoo,zipfile,virtual-memory,Python,Odoo,Zipfile,Virtual Memory,我一直在尝试使用Python3.6的zipfile模块创建一个包含多个对象的.zip文件。 我的问题是,我必须管理来自Odoo数据库的文件,该数据库只允许我使用字节对象而不是文件。 这是我当前的代码: import zipfile empty_zip_data = b'PK\x05\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' zip = zipfile.ZipFile(empty_zi


我一直在尝试使用Python3.6的zipfile模块创建一个包含多个对象的.zip文件。
我的问题是,我必须管理来自Odoo数据库的文件,该数据库只允许我使用
字节
对象而不是文件。

这是我当前的代码:

import zipfile

empty_zip_data = b'PK\x05\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
zip = zipfile.ZipFile(empty_zip_data, 'w')

# files is a list of tuples: [(u'file_name', b'file_data'), ...]
for file in files:
    file_name = file[0]
    file_data = file[1]
    zip.writestr(file_name, file_data)
将返回此错误:

File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/zipfile.py", line 1658, in writestr
  with self.open(zinfo, mode='w') as dest:
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/zipfile.py", line 1355, in open
  return self._open_to_write(zinfo, force_zip64=force_zip64)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/zipfile.py", line 1468, in _open_to_write
  self.fp.write(zinfo.FileHeader(zip64))
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/zipfile.py", line 723, in write
  n = self.fp.write(data)
AttributeError: 'bytes' object has no attribute 'write'
我该怎么做?我跟着那条路走了,但那没什么用…


编辑:使用
file\u data=file[1]。解码('utf-8')
作为第二个参数也没有用,我得到了相同的错误。

正如我在评论中提到的,问题在于这一行:

empty_zip_data = b'PK\x05\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
zip = zipfile.ZipFile(empty_zip_data, 'w')
您正试图将一个
byte
对象传递到
ZipFile()
方法中,但与
open()
类似,它需要一个类似路径的对象

在您的情况下,您可能希望利用
tempfile
模块(在这个特定示例中,我们将从下面使用:

请注意,使用上下文管理器可以确保加载后所有文件对象都正确关闭

这将为您提供
zipped_字节
,这是您要传递回Odoo的字节。您还可以通过将
zipped_字节
写入物理文件来测试它,首先查看它的外观:

with open('test.zip', 'wb') as zf:
    zf.write(zipped_bytes)

如果处理的文件大小相当大,请务必注意并使用

如果要在内存中处理所有这些内容而不使用临时文件,请使用
io.BytesIO
作为
ZipFile
的文件对象:

import io
from zipfile import ZIP_DEFLATED, ZipFile

file = io.BytesIO()
with ZipFile(file, 'w', ZIP_DEFLATED) as zip_file:
    for name, content in [
        ('file.dat', b'data'), ('another_file.dat', b'more data')
    ]:
        zip_file.writestr(name, content)

zip_data = file.getvalue()
print(zip_data)

您可能还希望设置如图所示的压缩算法,否则将使用默认值(无压缩!)。

问题不在于
ZipFile.writestr()
行,而在于
ZipFile.ZipFile(空的压缩数据,'w'))
line。这是因为
ZipFile
预期将
写入由
路径确定的文件,如
对象
空的zip\u数据
,但它是一个
字节
对象,没有
写入
方法。一种不雅观的方法是将zip文件临时写入物理本地首先,然后将其作为
字节读回,以传递回您的Odoo数据库。哇,经过难以置信的测试(无压缩!)后,如果不使用
ZIP\u DEFLATED
,这似乎是正确的。不会期望默认为无压缩。
import io
from zipfile import ZIP_DEFLATED, ZipFile

file = io.BytesIO()
with ZipFile(file, 'w', ZIP_DEFLATED) as zip_file:
    for name, content in [
        ('file.dat', b'data'), ('another_file.dat', b'more data')
    ]:
        zip_file.writestr(name, content)

zip_data = file.getvalue()
print(zip_data)