Python读取XLSX文件报错:Bad magic number for central directory
问题:读取S3下载的Excel文件时触发BadZipFile错误
需求目标
- 从AWS S3下载.xlsx文件至本地目录
- 将下载的.xlsx文件读取为pandas DataFrame
前置信息
- macOS、Windows、Linux系统下均出现相同报错
- 使用Python 3.8及3.9版本
- 已尝试的方法:
pd.read_excel(path_, engine=None, header=0, index_col=0)pd.read_excel(path_, engine='openpyxl', header=0, index_col=0)xlrd.open_workbook()- 直接用
ZipFile()打开文件
错误回溯
Traceback (most recent call last): File "C:\Users\User\AppData\Local\Programs\Python\Python39\lib\zipfile.py", line 1257, in __init__ self._RealGetContents() File "C:\Users\User\AppData\Local\Programs\Python\Python39\lib\zipfile.py", line 1352, in _RealGetContents raise BadZipFile("Bad magic number for central directory") zipfile.BadZipFile: Bad magic number for central directory
错误代码片段
centdir = fp.read(sizeCentralDir) if len(centdir) != sizeCentralDir: raise BadZipFile("Truncated central directory") centdir = struct.unpack(structCentralDir, centdir) if centdir[_CD_SIGNATURE] != stringCentralDir: raise BadZipFile("Bad magic number for central directory")
所用库版本
- pandas==1.4.3
- xlrd==2.0.1
- openpyxl==3.0.10
解决方案建议
1. 验证文件完整性
- 直接从AWS控制台手动下载目标文件,用Excel打开确认原文件是否正常。若原文件损坏,需重新上传正确文件到S3。
- 对比本地文件与S3文件的哈希值,确认下载过程无文件截断或篡改:
import boto3 import hashlib s3 = boto3.client('s3') # 获取S3文件的ETag(分块上传的文件ETag会带后缀,此时需重新计算S3文件哈希) s3_obj = s3.head_object(Bucket='你的存储桶名称', Key='你的文件路径.xlsx') s3_etag = s3_obj['ETag'].strip('"') # 计算本地文件MD5哈希 def calc_local_md5(file_path): md5_hash = hashlib.md5() with open(file_path, 'rb') as f: for chunk in iter(lambda: f.read(4096), b''): md5_hash.update(chunk) return md5_hash.hexdigest() local_md5 = calc_local_md5('本地文件路径.xlsx') print(f"S3文件ETag: {s3_etag}, 本地文件MD5: {local_md5}") - 若哈希不一致,使用boto3标准方法重新下载:
s3.download_file('你的存储桶名称', '你的文件路径.xlsx', '本地保存路径.xlsx')
2. 确认文件格式正确性
- 检查文件实际格式:.xlsx本质是Zip压缩包,用文本编辑器打开文件开头,正常内容应为
PK\x03\x04。若开头是其他内容,说明文件可能被错误命名(比如实际是CSV),需修改处理逻辑。 - 若文件是旧版.xls格式,注意xlrd 2.0+不再支持该格式,可降级xlrd到1.2.0,或使用openpyxl仅处理.xlsx文件。
3. 尝试修复损坏的Zip结构
如果文件确实是损坏的.xlsx,可尝试修复Zip结构后再读取:
from zipfile import ZipFile def repair_xlsx(corrupted_path, fixed_path): with ZipFile(corrupted_path, 'r') as src_zip: with ZipFile(fixed_path, 'w') as dest_zip: for entry in src_zip.infolist(): dest_zip.writestr(entry, src_zip.read(entry.filename)) repair_xlsx('损坏的文件.xlsx', '修复后的文件.xlsx')
修复完成后再用pd.read_excel尝试读取。
内容的提问来源于stack exchange,提问作者phybarin
相关产品推荐
相关产品推荐

