You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用pandas从S3读取Excel导入PostgreSQL时遭遇zipfile.BadZipFile与ValueError问题求助

解决S3 Excel导入PostgreSQL时的zipfile.BadZipFile/格式识别错误问题

我一眼就看出问题根源了——你在循环里重复调用io.BytesIO(obj['Body'].read()),但S3对象的Body流只能被读取一次!第一次读取后,流的指针就走到了末尾,后续再读得到的就是空字节,这就导致openpyxl解析空文件时抛出BadZipFile,不指定引擎时pandas识别不了空文件的格式,自然报错。

虽然你第一次用ExcelFile成功获取了工作表名称,但那是第一次读取流的有效内容,循环里的第二次读取已经拿不到任何数据了。

解决方案:预读取文件内容并复用

把S3对象的内容一次性读取到一个字节变量中,之后所有操作都基于这个变量,避免重复读取流。同时可以直接用ExcelFile对象来获取每个工作表的数据,不用再调用read_excel重复解析整个文件。

修改后的代码如下:

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

# 设置AWS环境变量(建议不要硬编码,用环境变量或AWS配置文件更安全)
os.environ["AWS_ACCESS_KEY_ID"] = "xxxxxxxxxxxx"
os.environ["AWS_SECRET_ACCESS_KEY"] = "xxxxxxxxxxxxxxxxxx"

# 初始化S3客户端并读取文件内容到字节变量
s3 = boto3.client('s3')
obj = s3.get_object(Bucket='bucket-name', Key='file.xlsx')
# 一次性读取所有内容到bytes变量,后续复用
file_content = obj['Body'].read()
data = pd.ExcelFile(io.BytesIO(file_content), engine='openpyxl')
print(data.sheet_names)

# 初始化数据库连接
engine1 = create_engine('postgresql://postgres:postgres@localhost:5432/postgres')

# 循环导入每个工作表
for idx, sheet_name in enumerate(data.sheet_names):
    # 直接从ExcelFile对象中获取工作表数据,无需重新解析整个文件
    df = data.parse(sheet_name)
    df.to_sql(f"test{idx}", engine1, index=False)

额外注意事项

  • 依赖包检查:确保你已经安装了openpyxl(用于读取.xlsx文件),如果是旧的.xls文件需要安装xlrd(注意xlrd 2.0+不再支持.xlsx,所以.xlsx必须用openpyxl)。可以用以下命令安装:
    pip install openpyxl pandas boto3 sqlalchemy psycopg2-binary
    
  • 安全建议:不要在代码中硬编码AWS密钥,建议使用AWS CLI配置文件、IAM角色(如果在EC2/ECS等AWS服务上运行)或环境变量来管理凭证。
  • 性能优化:如果Excel文件很大,可以考虑分块读取,但这个场景下先确保文件能正常读取再考虑优化。

内容的提问来源于stack exchange,提问作者Suraj221b

火山引擎 最新活动