【问题标题】:zipfile.BadZipFile: File is not a zip file when using "openpyxl" enginezipfile.BadZipFile:使用 \"openpyxl\" 引擎时文件不是 zip 文件
【发布时间】:2022-10-02 00:57:03
【问题描述】:

我创建了一个脚本,它将存储在 S3 中的 excel 表转储到我的本地 postgres 数据库中。我已经使用 pandas read_excel 和 ExcelFile 方法来读取 excel 表。 可以在此处找到相同的代码。

import boto3
import pandas as pd
import io
import os
from sqlalchemy import create_engine
import xlrd

os.environ[\"AWS_ACCESS_KEY_ID\"] = \"xxxxxxxxxxxx\"
os.environ[\"AWS_SECRET_ACCESS_KEY\"] = \"xxxxxxxxxxxxxxxxxx\"
s3 = boto3.client(\'s3\')

obj = s3.get_object(Bucket=\'bucket-name\', Key=\'file.xlsx\')
data = pd.ExcelFile(io.BytesIO(obj[\'Body\'].read()))
print(data.sheet_names)
a = len(data.sheet_names)

engine1 = create_engine(\'postgresql://postgres:postgres@localhost:5432/postgres\')
for i in range(a):
    df = pd.read_excel(io.BytesIO(obj[\'Body\'].read()),sheet_name=data.sheet_names[i], engine=\'openpyxl\')
    df.to_sql(\"test\"+str(i), engine1, index=False)

基本上,代码会解析 S3 存储桶并循环运行。对于每个工作表,它都会创建一个表格 并将工作表中的数据转储到该表中。

我遇到问题的地方是,当我运行这段代码时,我得到了这个错误。

df = pd.read_excel(io.BytesIO(obj[\'Body\'].read()),sheet_name=data.sheet_names[i-1], engine=\'openpyxl\')
zipfile.BadZipFile: File is not a zip file

这是在我在 read_excel 方法中添加了 \'openpyxl\' 引擎之后出现的。当我卸下引擎时,我收到此错误。

raise ValueError(
ValueError: Excel file format cannot be determined, you must specify an engine manually.

请注意,我可以打印到数据库的连接,所以连接没有问题,而且我使用的是最新版本的 python 和 pandas。此外,我可以获取 excel 文件中的所有 sheet_names,因此我也可以访问该文件。

非常感谢!

    标签: python pandas amazon-s3 boto3 python-zipfile


    【解决方案1】:

    您正在阅读obj 两次,完全:

    1. data = pd.ExcelFile(io.BytesIO(obj['Body'].read()))
    2. pd.read_excel(io.BytesIO(obj['Body'].read()), ...)

      您的对象只能是.read() 一次,第二次读取不会产生任何结果,一个空的b""

      为了避免多次重新读取 S3 流,您可以将其存储在 BytesIO 中一次,然后使用 seek 回退该 BytesIO。

      buf = io.BytesIO(obj["Body"].read())
      
      pd.ExcelFile(buf)
      
      buf.seek(0)
      
      pd.read_excel(buf, ...)
      
      # repeat
      

    【讨论】:

    • 我可以像这样删除它,obj['Body'].read()。但是你能告诉我如何在阅读后关闭第一个 obj 吗? PS:即使在删除 BytesIO 之后,我也会遇到同样的错误。
    • 好吧,你加载对象的内容两次,这是不必要且耗时的,你必须能够找到一种方法只加载一次,并传递它的数据。
    • 实际上它不是两次,它加载内容的次数与循环运行的次数一样多:_)。我现在明白所有其他运行都是无用的。
    • @ Suraj221b 查看我的编辑,您可以执行以下操作,文件从 S3 读取一次,并在您遍历工作表时保存在内存中。
    • 是的,谢谢你的回答。我在第一次读取后存储了数据,并在下一个 read_excel 中简单地传递了数据。 :)
    猜你喜欢
    • 2019-09-19
    • 1970-01-01
    • 2022-07-11
    • 1970-01-01
    • 1970-01-01
    • 2013-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多