Python操作.xls和.xlsx格式该分别用什么库

落日邮差
落日邮差
发布时间:2026-11-08| 4人浏览过
原创

详细讲解Python操作.xls和.xlsx两种Excel格式应分别选用什么库,深入分析底层格式差异、读写与修改场景下的工具选择、代码示例及常见报错排查方法。

在Python中处理Excel文件,核心原则是根据文件扩展名对应的底层格式分别选库:操作新版的 .xlsx 格式,读写与修改首选 openpyxl,只生成大体量或复杂样式报表可选 xlsxwriter;操作旧版的 .xls 格式,读取使用 xlrd,新建写入使用 xlwt,在已有文件上追加或修改则结合 xlutils。如果主要任务是批量数据分析或跨格式转换,可以使用 pandas 作为统一上层接口,但底层依然需要安装上述对应的引擎库。下面从格式差异、选库判断标准、具体代码操作到常见报错排查逐一展开说明。

一、为什么.xls和.xlsx不能混用同一个底层库

许多初学者在用Python读取Excel时会遇到格式不支持的报错,直接原因在于 .xls 和 .xlsx 虽然都显示为Excel表格,但内部存储结构完全不同,没有任何一套纯Python底层解析器会同时实现这两种格式的完整读写逻辑。

.xls 是Excel 97-2003时代使用的二进制格式(基于BIFF8规范),所有单元格数据、样式和工作表结构都以紧密的二进制流记录在复合文档中,单张工作表最多只能容纳65536行、256列。而 .xlsx 是Excel 2007之后采用的开发办公文档格式(OOXML标准),本质上是一个ZIP压缩包,解压后可以看到多个记录工作表数据、共享字符串和样式的XML文件,单表支持1048576行、16384列。

更关键的变化发生在 xlrd 库的2.0.0版本之后。早期 xlrd 曾同时支持读取 .xls 和 .xlsx,但由于解析XML存在潜在安全隐患且维护重心重叠,官方从2.0.0版本起彻底移除了对 .xlsx 的支持。因此,现在必须严格区分文件格式来搭配Python库。

Python操作.xls和.xlsx格式该分别用什么库
图1:.xls与.xlsx的底层存储结构差异及对应的Python操作库分工

二、按具体需求选择对应库的判断方法

在实际项目中,不仅要看文件后缀是 .xls 还是 .xlsx,还要区分你是“只读数据”“从零生成新表”还是“保留原表格式并修改部分单元格”。不同库在读写权限和样式保留能力上有明确边界。

Python操作.xls和.xlsx格式该分别用什么库
图2:根据文件格式与读写修改需求选择对应Python库的判断路径

总结起来,选择依据可以归纳为以下三条明确规则:

  • 处理 .xlsx 文件(当前主流场景):只要涉及读取、修改已有单元格、调整字体边框或插入行列,一律使用 openpyxl。只有在“不需要读取旧文件,仅从零生成包含大量图表、条件格式或几十万行数据的新 .xlsx 文件”时,才优先选用内存控制和图表支持更好的 xlsxwriter。
  • 处理 .xls 文件(兼容历史系统或老旧导出文件):只读提取数据使用 xlrd;从零生成 .xls 文件使用 xlwt;必须在原有 .xls 文件上修改数据并保存,需要同时安装 xlrd、xlwt 和 xlutils。
  • 以数据清洗、统计汇总为核心:不管源文件是 .xls 还是 .xlsx,不需要精细控制合并单元格或颜色边框时,直接使用 pandas,并在环境中安装好 openpyxl 和 xlrd 作为其底层引擎。

三、操作.xlsx格式:使用openpyxl完成读写与修改

openpyxl 是目前Python处理 .xlsx(以及启用宏的 .xlsm)最核心的库。它的工作对象依次是工作簿(Workbook)、工作表(Worksheet)和单元格(Cell)。需要注意的是,openpyxl 中所有行号和列号都按照Excel的习惯从 1 开始计数,而不是从 0 开始。

1. 安装环境准备

在命令行终端中执行以下pip命令安装 openpyxl:

pip install openpyxl

2. 新建、读取与追加修改.xlsx完整示例

下面的代码演示了在同一目录下先创建一份名为 sales_2026.xlsx 的文件,随后读取其中的数据,并在末尾追加一行新记录后保存。在项目工作目录中新建 handle_xlsx.py 并运行:

from openpyxl import Workbook, load_workbook
from openpyxl.styles import Font

file_path = "sales_2026.xlsx"

# 第一步:新建.xlsx工作簿并写入初始数据
wb = Workbook()
ws = wb.active
ws.title = "月度销量"

# 写入表头并设置加粗字体
ws.append(["月份", "产品名称", "销量", "单价"])
for col_idx in range(1, 5):
    ws.cell(row=1, column=col_idx).font = Font(bold=True)

# 写入两行示例数据
ws.append(["2026-01", "无线键盘", 120, 159.0])
ws.append(["2026-02", "机械鼠标", 95, 199.0])

wb.save(file_path)
print("1. 已创建文件:", file_path)

# 第二步:读取已有的.xlsx文件
# data_only=True 表示若单元格含公式则读取最后一次计算的数值结果
wb_read = load_workbook(file_path, data_only=True)
sheet = wb_read["月度销量"]

print("2. 读取到的表格内容:")
for row in sheet.iter_rows(min_row=1, values_only=True):
    print("  ", row)

# 第三步:在原表上修改单元格并追加新行
wb_edit = load_workbook(file_path)
edit_sheet = wb_edit["月度销量"]
# 修改第2行第3列(即2026-01的销量)为135
edit_sheet.cell(row=2, column=3, value=135)
# 在末尾追加一行
edit_sheet.append(["2026-03", "高清摄像头", 80, 249.0])
wb_edit.save(file_path)
print("3. 已完成修改与追加,当前总行数:", edit_sheet.max_row)
示例运行输出:1. 已创建文件: sales_2026.xlsx 2. 读取到的表格内容: ('月份', '产品名称', '销量', '单价') ('2026-01', '无线键盘', 120, 159.0) ('2026-02', '机械鼠标', 95, 199.0) 3. 已完成修改与追加,当前总行数: 4
容易出错的地方:用 load_workbook(file_path, data_only=True) 打开文件后,千万不要直接调用 save() 覆盖原文件。因为 data_only=True 会把所有公式替换为纯数值,一旦保存,原表格里的公式就会永久丢失。需要修改表格时应使用默认的 load_workbook(file_path)。

四、操作.xls格式:使用xlrd、xlwt与xlutils

面对政府申报系统、早期ERP或银行对账单导出的 .xls 文件,不能使用 openpyxl 打开。此时需要安装专门针对旧版二进制格式的工具组合。与 openpyxl 不同,xlrd 和 xlwt 的行号、列号索引全部从 0 开始计数。

1. 安装环境准备

在命令行终端中一次性安装读取、写入和修改所需的三个库:

pip install xlrd xlwt xlutils

2. 新建、读取与修改.xls完整示例

由于 xlwt 只能新建文件,无法直接打开已有 .xls 进行修改,如果需要修改已有 .xls 文件,必须先用 xlrd 读取工作簿,再通过 xlutils.copy.copy() 将其复制到内存中的可写对象,修改后再保存。新建 handle_xls.py 并运行:

import xlrd
import xlwt
from xlutils.copy import copy as xl_copy

xls_path = "legacy_inventory.xls"

# 第一步:使用 xlwt 新建 .xls 文件(行列索引从 0 开始)
wb_new = xlwt.Workbook(encoding="utf-8")
ws_new = wb_new.add_sheet("库存清单")

headers = ["编号", "配件名称", "库存数量"]
for col_idx, text in enumerate(headers):
    ws_new.write(0, col_idx, text)

ws_new.write(1, 0, "A001")
ws_new.write(1, 1, "散热风扇")
ws_new.write(1, 2, 50)

wb_new.save(xls_path)
print("1. 已生成旧版文件:", xls_path)

# 第二步:使用 xlrd 读取 .xls 文件
# formatting_info=True 用于保留原有单元格样式信息,供后续 xlutils 复制使用
rb = xlrd.open_workbook(xls_path, formatting_info=True)
r_sheet = rb.sheet_by_name("库存清单")

print("2. 读取到的行数:", r_sheet.nrows, "列数:", r_sheet.ncols)
for row_idx in range(r_sheet.nrows):
    print("  ", r_sheet.row_values(row_idx))

# 第三步:使用 xlutils.copy 在原文件基础上修改并追加数据
wb_modify = xl_copy(rb)
m_sheet = wb_modify.get_sheet(0)

# 将第2行(索引1)第3列(索引2)的库存数量从 50 改为 65
m_sheet.write(1, 2, 65)
# 在第3行(索引2)追加一条新记录
m_sheet.write(2, 0, "A002")
m_sheet.write(2, 1, "电源模块")
m_sheet.write(2, 2, 30)

wb_modify.save(xls_path)
print("3. 已完成对 legacy_inventory.xls 的更新保存")
示例运行输出:1. 已生成旧版文件: legacy_inventory.xls 2. 读取到的行数: 2 列数: 3 ['编号', '配件名称', '库存数量'] ['A001', '散热风扇', 50.0] 3. 已完成对 legacy_inventory.xls 的更新保存

细心的读者会发现,示例输出中整数 50 被 xlrd 读取成了浮点数 50.0。这是因为在旧版 .xls 的底层二进制存储中,普通整数和浮点数统一按双精度浮点数存储。如果需要还原为整数,可以在读取时检查单元格类型或用 int(val) 转换。

五、用pandas统一读取及将.xls安全转换为.xlsx

如果你不需要逐个调整单元格样式,只是想把表格读进Python做筛选、合并、分组统计,或者想把历史遗留的 .xls 批量转换成 .xlsx,使用 pandas 是最省力的做法。

pandas 通过 engine 参数指定底层解析库:读取 .xls 时指定 engine="xlrd",读写 .xlsx 时指定 engine="openpyxl"。此外,实际工作中经常遇到“文件后缀名叫 .xls,但内部其实是网页HTML表格、CSV文本或者重命名过的 .xlsx”的情况。直接按后缀调用库会立刻报错,因此在批量转换前,可以先读取文件前几个字节(文件头魔数)核对真实格式。

Python操作.xls和.xlsx格式该分别用什么库
图3:先校验文件头真实格式、再用pandas结合xlrd与openpyxl完成格式升级的操作流程

完整代码:检测文件真实格式并转换.xls到.xlsx

先确保已安装 pandas(以及前面安装过的 xlrd 和 openpyxl):

pip install pandas openpyxl xlrd

在相同目录下创建 convert_excel.py,该脚本会先检查前面生成的 legacy_inventory.xls 的文件头字节,确认是真实的二进制 .xls 后,将其全部工作表无损导出为 modern_inventory.xlsx:

import pandas as pd

def detect_excel_format(file_path):
    """通过文件前8个字节判断Excel文件的真实底层格式"""
    with open(file_path, "rb") as f:
        header = f.read(8)
    if header.startswith(b"\xd0\xcf\x11\xe0"):
        return "xls"
    elif header.startswith(b"PK\x03\x04"):
        return "xlsx"
    elif header.lstrip().startswith((b"<html", b"<HTML", b"<table", b"<TABLE")):
        return "html"
    return "unknown"

src_file = "legacy_inventory.xls"
dst_file = "modern_inventory.xlsx"

real_fmt = detect_excel_format(src_file)
print(f"检测到 {src_file} 的真实底层格式为: {real_fmt}")

if real_fmt == "xls":
    # sheet_name=None 表示读取所有工作表,返回 {表名: DataFrame} 字典
    all_sheets = pd.read_excel(src_file, sheet_name=None, engine="xlrd")
    with pd.ExcelWriter(dst_file, engine="openpyxl") as writer:
        for sheet_name, df in all_sheets.items():
            df.to_excel(writer, sheet_name=sheet_name, index=False)
    print(f"已将全部工作表转换并保存至: {dst_file}")

    # 验证转换后的.xlsx文件
    df_verify = pd.read_excel(dst_file, sheet_name="库存清单", engine="openpyxl")
    print("转换后读取验证:")
    print(df_verify)
示例运行输出:检测到 legacy_inventory.xls 的真实底层格式为: xls 已将全部工作表转换并保存至: modern_inventory.xlsx 转换后读取验证: 编号 配件名称 库存数量 0 A001 散热风扇 65 1 A002 电源模块 30

六、常见报错原因与排查方法

在混用 .xls 和 .xlsx 的过程中,最常遇到以下三类报错。根据报错提示中的关键词,可以迅速定位是选错了库还是文件本身名不副实:

1. 报错:xlrd.biffh.XLRDError: Excel xlsx file; not supported

  • 触发原因:使用了 2.0.0 及以上版本的 xlrd 去读取 .xlsx 格式的文件(或者在 pandas.read_excel() 中对 .xlsx 强行指定了 engine="xlrd")。
  • 解决方法:不要通过降级安装旧版 xlrd 来规避问题。正确的做法是将代码改用 openpyxl,或在 pandas.read_excel() 中设置 engine="openpyxl"。

2. 报错:openpyxl.utils.exceptions.InvalidFileException 或 zipfile.BadZipFile: File is not a zip file

  • 触发原因:用 openpyxl 打开了不支持的文件。常见于两种情况:一是直接把 .xls 文件传给了 openpyxl;二是有人把 .xls、.csv 或网页导出的表格直接手动重命名改成了 .xlsx 后缀,导致它根本不是合法的ZIP压缩包。
  • 解决方法:运行上一节中的 detect_excel_format() 函数检查文件头。若返回 xls,改用 xlrd 读取;若返回 html,说明是网页伪装的Excel,可使用 pandas.read_html() 解析;若是空文件(0字节),则需检查上游文件生成逻辑是否未正常调用 save()。

3. 报错:ValueError: row index was 65536, not allowed by .xls format

  • 触发原因:使用 xlwt 往 .xls 文件写入数据时,行数超过了65536行的格式上限。
  • 解决方法:这不是 xlwt 库的缺陷,而是 .xls 二进制规范本身的硬性限制。当数据量可能超过6万行时,必须改用 openpyxl(开启 write_only=True 只写模式)或 xlsxwriter 导出为 .xlsx 格式。

七、各库功能边界与选择总结

为了在日常开发中快速查阅,下表与总结图整理了Python操作 .xls 和 .xlsx 各主流库在读写权限、格式支持和典型用途上的核心差异:

库名称 支持格式 读取 新建写入 修改已有文件 样式与公式控制 最适合的使用场景
openpyxl .xlsx / .xlsm 支持 支持 支持 全面支持 日常读写、修改 .xlsx 单元格及样式的首选标准库
xlsxwriter .xlsx 不支持 支持 不支持 极强(仅写入) 从零生成含复杂图表、条件格式或超大行数的 .xlsx 报表
xlrd .xls(2.0+) 支持 不支持 不支持 仅基础格式读取 读取历史遗留或外部系统导出的旧版 .xls 文件
xlwt .xls 不支持 支持 不支持 支持基础样式 应旧系统要求必须生成 65536 行以内的 .xls 文件
xlutils .xls 需配 xlrd 需配 xlwt 支持(复制模式) 有限保留 在已有 .xls 文件基础上补充或修改少量单元格
pandas .xls / .xlsx 支持(配引擎) 支持(配引擎) 可追加工作表 弱(偏重纯数据) 批量数据清洗、多表聚合统计及 .xls 转 .xlsx
Python操作.xls和.xlsx格式该分别用什么库
图4:Python操作.xls与.xlsx在四大高频场景下的库选型对照总结

掌握上述对应关系后,遇到任何Excel处理任务时,只需先看清文件是 .xls 还是 .xlsx(必要时检验文件头),再按“.xlsx 主用 openpyxl、.xls 读写分用 xlrd/xlwt、批量分析用 pandas”的组合配置环境,就能稳定完成开发而不再被版本兼容问题困扰。

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。