是否可以从 zipfile 使用 openpyxl 加载 xlsx
Is it possible to load xlsx with openpyxl from zipfile
我正在尝试 openpyxl.load_workbook 从压缩的 zip 文件中提取 xlsx 文件,但它不起作用。以下代码在 openpyxl.load_workbook 和 "BadZipfile: File is not a zip file"
处失败
with zipfile.ZipFile(os.path.join(root, raw)) as z:
for file_info in z.infolist():
wb = openpyxl.load_workbook(z.open(file_info), read_only=True)
存档和其中的 excel 文件没有任何问题,就好像我将它解压缩到磁盘然后以下工作:
with open('report.xlsx') as f:
wb = openpyxl.load_workbook(f, read_only=True)
我可以使用此解决方案并将其临时解压缩到某处并加载 xslx,但想了解是否可以从 zipfile 加载它。
问题是 readonly=True
并不像您想象的那样。根据 docs:
Fortunately, there are two modes that enable you to read and write unlimited amounts of data with (near) constant memory consumption.
虽然没有明确说明,但我认为这涉及到内存映射文件(因为“持续内存消耗”)和随机访问(因为允许的操作范围)等价物。
无论哪种方式,设置 readonly=True
并不表示您只打算阅读一本工作簿(这就是 load_workbook
无论如何都可以做的,您必须覆盖现有的才能使任何变化”)。这表明您想要直接访问磁盘上的文件,而不加载全部内容。
ZipFile.open
不提供随机访问文件似乎很清楚(并且直觉上可以预期):
Note: The file-like object is read-only and provides the following methods: read()
, readline()
, readlines()
, __iter__()
, next()
.
此列表中未提及 seek
的事实很能说明问题(双关语只是有点意思)。
您可以通过将有问题的行一分为二来获得有关异常的更多信息(一种对嵌套函数调用有用的通用调试技术):
x = z.open(file_info)
wb = openpyxl.load_workbook(x, readonly=True)
您会注意到错误发生在这两行中的第二行。这是因为几乎所有的 Microsoft 开放文档格式实际上都只是奇特的 zip 文件。问题很可能是 openpyxl 无法以随机访问模式打开您的文件,而不是它实际上是一个无效的 zip 文件。
不管怎样,这是一堆非常有根据的猜测,导致了一个简单的、一个关键字删除的解决方案:
TL;DR
在读取非随机访问数据(如压缩 zip 条目)时删除 readonly=True
:
wb = openpyxl.load_workbook(z.open(file_info))
附录
您应该养成编写最小程序来展示您的问题的习惯,这样回答您问题的人就可以专注于完成他们的工作,而不是因为生气而关闭本来是一个非常好的问题。我非常喜欢你的问题,因此可以为你做这个,所以这里有一个最小的程序来演示你的问题,只需要复制并粘贴到 运行:
import openpyxl, zipfile
from openpyxl.workbook.workbook import Workbook
wb = Workbook()
wb.active['A1'] = 12
wb.active['A2'] = 13
wb.save('report.xlsx')
with zipfile.ZipFile('test.zip', 'w') as z:
z.write('report.xlsx')
with open('report.xlsx') as f:
wb = openpyxl.load_workbook(f, read_only=True)
print(wb.active['A1'].value)
print(wb.active['A2'].value)
with zipfile.ZipFile('test.zip', 'r') as z:
for file_info in z.infolist():
x = z.open(file_info, 'r')
wb = openpyxl.load_workbook(x, readonly=True)
print(wb.active['A1'].value)
print(wb.active['A2'].value)
我正在尝试 openpyxl.load_workbook 从压缩的 zip 文件中提取 xlsx 文件,但它不起作用。以下代码在 openpyxl.load_workbook 和 "BadZipfile: File is not a zip file"
处失败with zipfile.ZipFile(os.path.join(root, raw)) as z:
for file_info in z.infolist():
wb = openpyxl.load_workbook(z.open(file_info), read_only=True)
存档和其中的 excel 文件没有任何问题,就好像我将它解压缩到磁盘然后以下工作:
with open('report.xlsx') as f:
wb = openpyxl.load_workbook(f, read_only=True)
我可以使用此解决方案并将其临时解压缩到某处并加载 xslx,但想了解是否可以从 zipfile 加载它。
问题是 readonly=True
并不像您想象的那样。根据 docs:
Fortunately, there are two modes that enable you to read and write unlimited amounts of data with (near) constant memory consumption.
虽然没有明确说明,但我认为这涉及到内存映射文件(因为“持续内存消耗”)和随机访问(因为允许的操作范围)等价物。
无论哪种方式,设置 readonly=True
并不表示您只打算阅读一本工作簿(这就是 load_workbook
无论如何都可以做的,您必须覆盖现有的才能使任何变化”)。这表明您想要直接访问磁盘上的文件,而不加载全部内容。
ZipFile.open
不提供随机访问文件似乎很清楚(并且直觉上可以预期):
Note: The file-like object is read-only and provides the following methods:
read()
,readline()
,readlines()
,__iter__()
,next()
.
此列表中未提及 seek
的事实很能说明问题(双关语只是有点意思)。
您可以通过将有问题的行一分为二来获得有关异常的更多信息(一种对嵌套函数调用有用的通用调试技术):
x = z.open(file_info)
wb = openpyxl.load_workbook(x, readonly=True)
您会注意到错误发生在这两行中的第二行。这是因为几乎所有的 Microsoft 开放文档格式实际上都只是奇特的 zip 文件。问题很可能是 openpyxl 无法以随机访问模式打开您的文件,而不是它实际上是一个无效的 zip 文件。
不管怎样,这是一堆非常有根据的猜测,导致了一个简单的、一个关键字删除的解决方案:
TL;DR
在读取非随机访问数据(如压缩 zip 条目)时删除 readonly=True
:
wb = openpyxl.load_workbook(z.open(file_info))
附录
您应该养成编写最小程序来展示您的问题的习惯,这样回答您问题的人就可以专注于完成他们的工作,而不是因为生气而关闭本来是一个非常好的问题。我非常喜欢你的问题,因此可以为你做这个,所以这里有一个最小的程序来演示你的问题,只需要复制并粘贴到 运行:
import openpyxl, zipfile
from openpyxl.workbook.workbook import Workbook
wb = Workbook()
wb.active['A1'] = 12
wb.active['A2'] = 13
wb.save('report.xlsx')
with zipfile.ZipFile('test.zip', 'w') as z:
z.write('report.xlsx')
with open('report.xlsx') as f:
wb = openpyxl.load_workbook(f, read_only=True)
print(wb.active['A1'].value)
print(wb.active['A2'].value)
with zipfile.ZipFile('test.zip', 'r') as z:
for file_info in z.infolist():
x = z.open(file_info, 'r')
wb = openpyxl.load_workbook(x, readonly=True)
print(wb.active['A1'].value)
print(wb.active['A2'].value)