解决假XLS文件头错误:降级Python环境实现真·XLS格式导出
本文记录一次真实业务排障全过程:后缀是.xls、实际是CSV、文件头错误、必须输出标准XLS、新版Python无法写入的终极解决方案。适合处理旧系统、legacy工具、必须兼容Excel 97-2003格式的场景。
一、问题背景
业务场景需要批量处理一批表格文件:
- 文件后缀:
.xls - 来源:旧系统导出
- 问题:无法被正常Excel库解析,列错位、乱码
- 强制要求:输出必须是真·XLS格式(后续工具只认XLS,不支持XLSX)
- 开发环境:Windows / MacOS + Python
二、关键报错:直接暴露真相
最开始用常规方式读取.xls时,直接报错:
xlrd.biffh.XLRDError: Unsupported format, or corrupt file: Expected BOF record; found b'"\xd3\xc3\xbb\xa7\xb1\xe0\xba'
报错解读
Expected BOF record:真正的XLS必须以BOF文件头开头found b'...中文...':文件内容实际是GBK文本
结论
这是假XLS: CSV文本文件 → 改后缀为.xls → 骗过Excel,但骗不过文件头校验。
三、中间踩过的所有坑(避坑必读)
1. 用pandas直接读取CSV
能读,但出现:
- 列全部挤在第二列
- 行首空列、首行偏移
- 分隔符识别失败
2. 导出XLSX再改后缀为XLS
完全不可用!
- XLSX = ZIP压缩包格式
- XLS = BIFF二进制格式
- 改后缀只是自欺欺人
- 文件头依旧错误,后续工具直接拒绝读取
3. 新版Python无法写XLS
Python 3.10+ / pandas 1.4+ 之后:
- 移除
xlwt支持 - 不再支持写入.xls
- 无论怎么装库都会报错:
ValueError: No Excel writer 'xlwt'
四、问题真正症结(一句话总结)
- 源文件:假XLS,真CSV(无合法Excel文件头)
- 目标格式:真·XLS(Excel 97-2003,必须带BOF头)
- 现代Python生态:已彻底放弃XLS写入
- 唯一出路:降级环境 + 使用xlwt
五、最终解决方案:固定版本环境
这是纯代码、不依赖Excel软件、可打包EXE分发的唯一可行方案。
固定版本组合
Python 3.8 (最后支持xlwt的稳定版)
pandas 1.3.5 最后支持xlwt引擎
xlwt 1.3.0 唯一能生成真XLS的库
xlrd 1.2.0
安装命令
pip install pandas==1.3.5 xlwt==1.3.0 xlrd==1.2.0 openpyxl
六、最终可用脚本(可直接生产使用)
功能:
- 接收目录参数,批量处理
- 自动修复:列错位、空列、中文乱码、首行偏移
- 输出标准XLS(带正确BOF文件头)
- 不修改原文件、不保留中间文件
# -*- coding: utf-8 -*-
import sys
import os
import pandas as pd
def convert_to_real_xls(file_path):
base, ext = os.path.splitext(file_path)
output_file = base + ".xls"
try:
# 以CSV方式读取假XLS文件
df = pd.read_csv(
file_path,
encoding="gbk",
sep=None,
engine="python",
on_bad_lines="skip",
skip_blank_lines=True
)
# 清理空列、错列
df = df.dropna(how="all", axis=1)
df = df.loc[:, ~df.columns.str.contains("^Unnamed")]
# 写入真正的XLS(正确文件头)
df.to_excel(
output_file,
index=False,
engine="xlwt"
)
print(f"✅ 转换成功:{output_file}")
except Exception as e:
print(f"❌ 处理失败:{file_path} => {str(e)}")
def process_folder(folder_path):
if not os.path.isdir(folder_path):
print(f"❌ 目录不存在:{folder_path}")
return
file_list = [f for f in os.listdir(folder_path) if f.lower().endswith(".xls")]
if not file_list:
print("ℹ️ 当前目录无 xls 文件")
return
print(f"📂 找到 {len(file_list)} 个文件,开始修复...\n")
for filename in file_list:
full_path = os.path.join(folder_path, filename)
convert_to_real_xls(full_path)
if __name__ == "__main__":
print("=== XLS 假文件修复工具(输出真·XLS格式) ===")
if len(sys.argv) < 2:
# print("使用方法:python fix_xls.py 目录路径")
# print("示例:python fix_xls.py .")
print("使用方法:cvt.exe 目录路径")
print("示例:evt.exe .")
sys.exit(1)
process_folder(sys.argv[1])
七、运行方式
python fix_xls.py .
八、验证是否为“真XLS”
用记事本/十六进制工具打开生成的.xls,前4字节必须是:
D0 CF 11 E0
这是 Excel 97-2003 标准BOF文件头,所有旧系统/工具均可识别。
九、打包成EXE分发(Windows)
使用 pyinstaller
pip install pyinstaller
pyinstaller --onefile --console --clean --name cvt.exe fix_xls.py
生成路径:
dist/cvt.exe
可直接在无Python环境的Windows上运行。
⚠️:在 MacOS 上打包后在 Window 上打包会出现 ""
十、核心经验总结(干货)
- 文件后缀不可信,文件头才是唯一标识
- CSV改后缀 ≠ XLS,Excel能打开是因为容错,不是格式合法
- XLS 与 XLSX 是完全不同的格式,不能靠改后缀兼容
- 现代Python无法写XLS,必须降级到Python3.8 + xlwt
- 真XLS标志:文件头 D0 CF 11 E0
- 旧系统依赖XLS是常态,降级环境是最稳定、最可移植的方案
十一、适用场景
- 旧系统/银行/政府/legacy工具只认XLS
- 文件为CSV改后缀导致的文件头错误
- 需要批量修复列错位、乱码
- 需要生成可分发EXE工具
- Mac/Windows跨平台开发