如何解决从FTP内存读取.xlsx为Pandas DataFrame时的KeyError?
解决从FTP读取xlsx到Pandas DataFrame的报错问题
报错原因分析
KeyError: "There is no item named 'xl/sharedStrings.xml' in the archive" 通常由以下情况导致:
- 读取了非xlsx格式文件(比如xls、txt、目录等),这类文件不符合xlsx的压缩包结构
- 循环中复用同一个
BytesIO对象,导致多个文件内容叠加,破坏了xlsx的结构 - 目标xlsx文件本身损坏或为空
针对性解决方案
1. 筛选有效xlsx文件
只处理后缀为.xlsx的文件,同时排除目录(通过文件大小判断,目录的ftp.size()返回None):
# 替换原listff的生成逻辑 listff = [] for f in ftp.nlst(): try: if ftp.size(f) is not None and f.lower().endswith('.xlsx'): listff.append(f) except ftplib.error_perm: # 跳过无权限访问的目录或文件 continue
2. 每次循环重置BytesIO
避免多个文件内容叠加,在循环内创建新的BytesIO对象,确保每次读取的是单一文件的内容。
3. 指定正确的读取引擎
处理xlsx文件需使用openpyxl引擎,提前执行pip install openpyxl安装依赖。
修改后的完整代码
import ftplib import pandas as pd from io import BytesIO ftp = ftplib.FTP("host") ftp.login("ftp_111", "hs12121") ftp.dir() # 筛选有效xlsx文件 listff = [] for f in ftp.nlst(): try: if ftp.size(f) is not None and f.lower().endswith('.xlsx'): listff.append(f) except ftplib.error_perm: continue for filename in listff: try: # 每次循环创建新的BytesIO,避免内容污染 flo = BytesIO() ftp.retrbinary(f'RETR {filename}', flo.write, 1024) flo.seek(0) # 指定openpyxl引擎读取xlsx df = pd.read_excel(flo, engine='openpyxl') print(f"文件 {filename} 读取成功,DataFrame形状:{df.shape}") # 此处添加你的DataFrame处理逻辑 except Exception as e: print(f"处理文件 {filename} 出错: {str(e)}")
额外说明
- 若需处理xls文件,可单独筛选
.xls后缀,使用engine='xlrd'读取(注意xlrd 2.0+版本不再支持xlsx,需安装xlrd<2.0或pyxlsb引擎) - 若仍报错,需检查目标xlsx文件是否损坏,可手动下载后验证文件有效性
内容的提问来源于stack exchange,提问作者rinat akhtyamov
相关产品推荐
相关产品推荐

