Python3.6 的 Zipfile 模块:写入字节而不是 Odoo 的文件
Zipfile module for Python3.6: write to Bytes instead of Files for Odoo
我一直在尝试使用 Python 3.6 的 zipfile 模块来创建一个包含多个对象的 .zip 文件。
我的问题是,我必须管理 Odoo 数据库中的文件,该数据库只允许我使用 bytes
对象而不是文件。
这是我当前的代码:
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)
其中returns这个错误:
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'
我应该怎么做?我跟着ZipFile.writestr() docs,但那让我无处可去...
编辑:使用 file_data = file[1].decode('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
模块(在这个特定示例中,我们将使用 SpooledTemporaryFile
from this :
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'
注意使用上下文管理器来确保所有文件对象在加载后正确关闭。
这给你 zipped_bytes
这是你想要传回 Odoo 的字节。您还可以通过将 zipped_bytes
写入物理文件来测试它,先看看它是什么样子:
with open('test.zip', 'wb') as zf:
zf.write(zipped_bytes)
如果您正在处理相当大的文件,请务必注意并使用 max_size
argument in the documentation.
如果你想在没有临时文件的情况下在内存中处理所有这些,那么使用 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)
您可能还需要如图所示设置压缩算法,否则将使用默认值(无压缩!)。
我一直在尝试使用 Python 3.6 的 zipfile 模块来创建一个包含多个对象的 .zip 文件。
我的问题是,我必须管理 Odoo 数据库中的文件,该数据库只允许我使用 bytes
对象而不是文件。
这是我当前的代码:
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)
其中returns这个错误:
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'
我应该怎么做?我跟着ZipFile.writestr() docs,但那让我无处可去...
编辑:使用 file_data = file[1].decode('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
模块(在这个特定示例中,我们将使用 SpooledTemporaryFile
from this
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'
注意使用上下文管理器来确保所有文件对象在加载后正确关闭。
这给你 zipped_bytes
这是你想要传回 Odoo 的字节。您还可以通过将 zipped_bytes
写入物理文件来测试它,先看看它是什么样子:
with open('test.zip', 'wb') as zf:
zf.write(zipped_bytes)
如果您正在处理相当大的文件,请务必注意并使用 max_size
argument in the documentation.
如果你想在没有临时文件的情况下在内存中处理所有这些,那么使用 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)
您可能还需要如图所示设置压缩算法,否则将使用默认值(无压缩!)。