1. 为什么需要处理旧版Excel (.xls)文件?
在企业数据迁移和传统系统维护场景中,我们经常会遇到2003年以前生成的.xls格式文件。这种二进制文件格式虽然已被微软淘汰,但至今仍广泛存在于财务系统、医疗档案等对格式稳定性要求极高的领域。我去年参与某银行历史数据迁移项目时,就遇到过需要解析15年前生成的贷款记录文件的情况。
与新版.xlsx采用的XML压缩格式不同,.xls文件使用BIFF(Binary Interchange File Format)编码。这种格式最大的特点是:
- 文件结构包含Workbook、Worksheet等二进制记录流
- 单元格数据以特定字节标记存储
- 最大支持65536行×256列的数据量
2. 核心工具选型与对比
2.1 xlrd/xlwt组合方案
这对黄金搭档是处理.xls文件最经典的方案。我在处理2010年之前的财务报表时,xlrd的稳定性从未让我失望过。安装只需一行命令:
bash复制pip install xlrd==1.2.0 xlwt
实际读取示例:
python复制import xlrd
# 打开1997-2003格式的Excel文件
book = xlrd.open_workbook("legacy_data.xls")
# 获取第一个工作表
sheet = book.sheet_by_index(0)
# 读取A1单元格
cell_value = sheet.cell_value(0, 0)
写入操作需要注意格式控制:
python复制import xlwt
workbook = xlwt.Workbook(encoding='utf-8')
sheet = workbook.add_sheet('Sheet1')
# 设置字体样式
style = xlwt.XFStyle()
font = xlwt.Font()
font.bold = True
style.font = font
# 写入带样式的数据
sheet.write(0, 0, '重要数据', style)
workbook.save('output.xls')
注意:xlrd 2.0+版本已移除.xls支持,必须指定1.2.0版本
2.2 pandas的兼容方案
虽然pandas主要依赖openpyxl处理新格式,但通过指定引擎仍可支持旧格式:
python复制import pandas as pd
# 读取
df = pd.read_excel("old_file.xls", engine='xlrd')
# 写入
df.to_excel("new_old_format.xls", engine='xlwt', index=False)
实测对比:
| 操作类型 | xlrd/xlwt | pandas包装层 |
|---|---|---|
| 读取速度 | 快(直接二进制解析) | 稍慢(需DataFrame转换) |
| 写入功能 | 支持完整格式控制 | 仅基础数据写入 |
| 内存占用 | 低 | 较高(需加载全部数据) |
3. 实战中的典型问题解决方案
3.1 编码问题处理
早期.xls文件常使用本地化编码(如GB2312),建议统一转码:
python复制from xlrd import open_workbook
def safe_cell_value(cell):
if isinstance(cell.value, str):
try:
return cell.value.encode('latin1').decode('gbk')
except:
return cell.value
return cell.value
book = open_workbook('gbk_encoded.xls')
sheet = book.sheet_by_index(0)
print(safe_cell_value(sheet.cell(0,0)))
3.2 合并单元格处理
旧格式的合并单元格需要特殊解析:
python复制merged_cells = sheet.merged_cells
for (rlo, rhi, clo, chi) in merged_cells:
if row_idx >= rlo and row_idx < rhi:
if col_idx >= clo and col_idx < chi:
value = sheet.cell_value(rlo, clo)
3.3 日期转换陷阱
Excel的日期存储为1900年以来的天数(但存在1900年闰年bug):
python复制from datetime import datetime, timedelta
def excel_date_to_python(date_num):
if date_num > 59:
date_num -= 1 # 修正1900年闰年错误
return datetime(1899, 12, 30) + timedelta(days=date_num)
4. 高级应用场景
4.1 大数据量分块处理
对于接近65536行限制的文件,建议分块读取:
python复制chunk_size = 5000
for i in range(0, sheet.nrows, chunk_size):
chunk = [sheet.row_values(j) for j in range(i, min(i+chunk_size, sheet.nrows))]
process_chunk(chunk)
4.2 与新版Excel的互操作
转换到新格式的建议工作流:
- 用xlrd读取旧文件
- 用openpyxl创建新工作簿
- 按需迁移数据和格式
python复制from openpyxl import Workbook
new_wb = Workbook()
new_ws = new_wb.active
for row in range(sheet.nrows):
for col in range(sheet.ncols):
new_ws.cell(row=row+1, column=col+1).value = sheet.cell_value(row, col)
5. 性能优化技巧
通过实践总结的提速方法:
- 禁用格式检查(提升20%读取速度):
python复制book = xlrd.open_workbook("file.xls", formatting_info=False)
- 批量写入数据时先收集再写入:
python复制data_buffer = []
for item in big_dataset:
data_buffer.append(process_item(item))
for i, row in enumerate(data_buffer):
for j, value in enumerate(row):
sheet.write(i, j, value)
- 使用临时文件减少内存占用:
python复制import tempfile
with tempfile.NamedTemporaryFile() as tmp:
workbook.save(tmp.name)
post_process(tmp.name)
在处理某制造业十年生产数据时,这些技巧帮助我将处理时间从3小时缩短到25分钟。特别提醒:xlwt不支持修改已有文件,必须全量写入,对于大文件要特别注意内存管理。
