简体   繁体   English

适用于Python3.6的Zipfile模块:写字节而不是Odoo文件

[英]Zipfile module for Python3.6: write to Bytes instead of Files for Odoo


I've been trying to use the zipfile module for Python 3.6 to create a .zip file which contains multiple objects. 我一直在尝试使用适用于Python 3.6的zipfile模块来创建一个包含多个对象的.zip文件。
My problem is, I have to manage files from an Odoo database that only allows me to use bytes objects instead of files. 我的问题是,我必须管理仅允许我使用bytes对象而不是文件的Odoo数据库中的文件。

This is my current code: 这是我当前的代码:

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)

Which returns this error: 哪个返回此错误:

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'

How am I supposed to do it? 我应该怎么做? I followed the ZipFile.writestr() docs , but that got me nowhere... 我遵循了ZipFile.writestr()docs ,但是这使我无处可...

EDIT: using file_data = file[1].decode('utf-8') as second parameter is not useful either, I get the same error. 编辑:使用file_data = file[1].decode('utf-8')作为第二个参数也没有用,我得到同样的错误。

As mentioned in my comment, the issue is with this line: 如我的评论中所述,问题在于以下这一行:

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')

You're trying to pass a byte object into the ZipFile() method, but like open() it is expecting a path-like object. 您正在尝试将byte对象传递到ZipFile()方法中,但是像open()它期望使用类似路径的对象。

In your case, you might want to utilize the tempfile module (in this particular example we'll use SpooledTemporaryFile from this relevant question : 在您的情况下,您可能想利用tempfile模块(在此特定示例中,我们将从以下相关问题中使用SpooledTemporaryFile

import tempfile
import zipfile

# Create a virtual temp file
with tempfile.SpooledTemporaryFile() as tp:

    # pass the temp file for zip File to open
    with zipfile.ZipFile(tp, 'w') as zip:
        files = [(u'file_name', b'file_data'), (u'file_name2', b'file_data2'),]
        for file in files:
            file_name = file[0]
            file_data = file[1]
            zip.writestr(file_name, file_data)

    # Reset the cursor back to beginning of the temp file
    tp.seek(0)
    zipped_bytes = tp.read()

zipped_bytes
# b'PK\x03\x04\x14\x00\x00\x00\x00\x00\xa8U ... \x00\x00'

Note the use of context managers to ensure all your file objects are closed properly after being loaded. 请注意使用上下文管理器来确保所有文件对象在加载后都正确关闭。

This gives you zipped_bytes which is the bytes you want to pass back to Odoo. 这为您提供了zipped_bytes ,这是您要传递回Odoo的字节。 You can also test the zipped_bytes by writing it to a physical file to see what it looks like first: 您还可以通过将zipped_bytes写入物理文件来测试它的zipped_bytes ,从而对其进行测试:

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

If you are handling file size that are considerably large, make sure to pay attention and make use of max_size argument in the documentation. 如果要处理的文件太大,请确保注意并使用文档中max_size参数。

If you want to handle all of this in memory without a temporary file then use io.BytesIO as the file object for ZipFile : 如果要在没有临时文件的情况下处理内存中的所有这些,则可以使用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)

You may also want to set the compression algorithm as shown because otherwise the default (no compression!) is used. 您可能还需要设置如图所示的压缩算法,因为否则将使用默认值(不压缩!)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM