导航菜单

  • 1.vector
  • 2.milvus
  • 3.pymilvus
  • 4.rag
  • 5.rag_measure
  • 7.search
  • ragflow
  • heapq
  • HNSW
  • cosine_similarity
  • math
  • typing
  • etcd
  • minio
  • collections
  • jieba
  • random
  • beautifulsoup4
  • chromadb
  • sentence_transformers
  • numpy
  • lxml
  • openpyxl
  • PyMuPDF
  • python-docx
  • requests
  • python-pptx
  • text_splitter
  • all-MiniLM-L6-v2
  • openai
  • llm
  • BPETokenizer
  • Flask
  • RAGAS
  • BagofWords
  • langchain
  • Pydantic
  • abc
  • faiss
  • MMR
  • scikit-learn
  • 1. 什么是 OpenPyXL?
  • 2. 环境准备
    • 2.1 检查 Python 版本
    • 2.2 安装 OpenPyXL
    • 2.3 验证安装
  • 3. 核心概念
    • 3.1 Workbook(工作簿)
    • 3.2 Worksheet(工作表)
    • 3.3 Cell(单元格)
    • 3.4 坐标系统
  • 4. 快速体验:创建和读取工作簿
    • 4.1 创建工作簿
    • 4.2 读取工作簿
  • 5. 工作簿与工作表管理
    • 5.1 创建和删除工作表
    • 5.2 复制工作表
  • 6. 单元格读写:多种方式访问单元格
    • 6.1 通过坐标访问单元格
    • 6.2 批量添加数据
    • 6.3 遍历单元格
  • 7. 样式设置:美化工作表
    • 7.1 字体和颜色
    • 7.2 对齐和边框
    • 7.3 行高和列宽
  • 8. 公式计算
    • 8.1 基本公式
    • 8.2 常用公式示例
  • 9. 读取大文件:优化性能
    • 9.1 只读模式读取
  • 10. 实战案例:销售报表生成器
  • 11. 常见问题与排查
    • 11.1 文件损坏问题
    • 11.2 中文字体显示问题
    • 11.3 公式不计算问题
    • 11.4 性能优化建议
  • 12. 参考

1. 什么是 OpenPyXL? #

OpenPyXL 是 Python 中最流行的 Excel 文件处理库之一,专门用于读写 Excel 2007 及更高版本的文件格式(.xlsx、.xlsm、.xltx、.xltm)。它支持创建、读取、修改 Excel 文件,还能设置样式、添加公式、插入图表等功能。

为什么要用 OpenPyXL?

想象一下,你需要批量处理 Excel 文件、生成报表、或者从 Excel 中提取数据进行分析。手动操作太慢且容易出错,而 OpenPyXL 提供了强大的 Python API,可以自动化完成这些任务。

OpenPyXL 的优势:

  • 功能强大:支持读写、样式、公式、图表等所有常见操作
  • 纯 Python 实现:不需要安装 Microsoft Excel
  • 跨平台:Windows、macOS、Linux 都可以使用
  • 易于学习:API 设计简洁直观,文档完善
  • 兼容性好:支持 Excel 2007 及以上版本

前置知识补充:

  • Excel 文件结构:Excel 文件(.xlsx)由工作簿(Workbook)组成,每个工作簿可以包含多个工作表(Worksheet),每个工作表由单元格(Cell)组成。单元格是行和列的交集,比如 A1、B2 等。
  • 坐标系统:Excel 使用字母(A、B、C...)表示列,使用数字(1、2、3...)表示行。比如 A1 表示第一行第一列的单元格,B2 表示第二行第二列的单元格。
  • 工作表(Worksheet):一个工作簿可以包含多个工作表,每个工作表可以独立编辑。在 Excel 中,你可以在底部看到多个工作表标签。
  • 工作簿(Workbook):整个 Excel 文件就是一个工作簿,它包含所有的工作表和数据。

2. 环境准备 #

在学习 OpenPyXL 之前,需要确保你的 Python 环境已经准备好。OpenPyXL 支持 Python 3.7 及以上版本。

2.1 检查 Python 版本 #

在安装之前,先检查一下你的 Python 版本是否符合要求。

# Windows PowerShell:查看 Python 版本
python --version
# macOS 终端:查看 Python 版本
python3 --version

2.2 安装 OpenPyXL #

OpenPyXL 可以直接通过 pip 安装。安装过程会自动下载所需的依赖包。

# 说明:Windows PowerShell 安装 OpenPyXL
# 先升级 pip 到最新版本,确保能正常安装依赖
python -m pip install --upgrade pip
# 安装 openpyxl 库
python -m pip install openpyxl
# 说明:macOS / Linux 终端安装 OpenPyXL
# 先升级 pip 到最新版本
python3 -m pip install --upgrade pip
# 安装 openpyxl 库
python3 -m pip install openpyxl

网络加速提示:如果从 PyPI 下载较慢,可以使用国内镜像:

  • Windows: python -m pip install openpyxl -i https://pypi.tuna.tsinghua.edu.cn/simple
  • macOS: python3 -m pip install openpyxl -i https://pypi.tuna.tsinghua.edu.cn/simple

安装问题提示:

  • 如果安装失败,可能是因为网络问题。可以尝试使用镜像源,或者检查网络连接。
  • macOS 用户如果遇到权限问题,可以在命令前加 sudo(不推荐),或者使用虚拟环境。

2.3 验证安装 #

安装完成后,验证一下是否安装成功。

# -*- coding: utf-8 -*-
# 说明:验证 OpenPyXL 是否安装成功

# 说明:导入 openpyxl 库
# openpyxl 是用于处理 Excel 文件的核心库
import openpyxl

# 说明:打印 OpenPyXL 版本信息
# __version__ 属性返回库的版本号
print(f"OpenPyXL 版本:{openpyxl.__version__}")

# 说明:测试创建工作簿
# Workbook() 创建一个新的空工作簿对象
wb = openpyxl.Workbook()

# 说明:获取默认工作表
# active 属性返回当前活动的工作表
ws = wb.active

# 说明:在工作表中写入一个测试值
# 通过坐标(如 A1)直接赋值可以写入数据
ws["A1"] = "测试"

# 说明:读取单元格的值
# 同样可以通过坐标读取单元格的值
value = ws["A1"].value

# 说明:打印结果,验证安装是否成功
print("安装成功!单元格 A1 的值:", value)

# 说明:如果没有报错并输出了"测试",说明安装成功

3. 核心概念 #

在使用 OpenPyXL 之前,需要理解几个核心概念。这些概念是理解 OpenPyXL 的基础。

3.1 Workbook(工作簿) #

Workbook 是 Excel 文件的对象表示,相当于整个 Excel 文件。你可以通过 Workbook() 创建新的工作簿,或通过 load_workbook() 加载已有的工作簿。

3.2 Worksheet(工作表) #

Worksheet 是工作簿中的一个工作表,类似于 Excel 中的标签页。一个工作簿可以包含多个工作表,每个工作表都可以独立编辑。

3.3 Cell(单元格) #

Cell 是工作表中的一个单元格,是数据存储的基本单位。每个单元格都有一个唯一的坐标,如 A1、B2 等。

3.4 坐标系统 #

OpenPyXL 使用 Excel 的坐标系统:列用字母(A、B、C...)表示,行用数字(1、2、3...)表示。你也可以使用数字坐标,列从 1 开始。

4. 快速体验:创建和读取工作簿 #

让我们通过一个最简单的例子来快速体验 OpenPyXL 的强大功能。

4.1 创建工作簿 #

本代码块中使用的 OpenPyXL 方法:

方法/属性 功能说明 常用参数 返回值
Workbook() 创建一个新的空工作簿 无 Workbook 对象
.active 获取当前活动的工作表 无(属性) Worksheet 对象
.title 获取或设置工作表的名称 无(属性),可直接赋值 字符串
ws[坐标] 通过坐标访问单元格 坐标:如 "A1" Cell 对象
.save() 保存工作簿到文件 filename:文件路径 无
# -*- coding: utf-8 -*-
# 说明:快速体验 OpenPyXL - 创建工作簿

# 说明:导入 openpyxl 库
# 从 openpyxl 导入 Workbook 类,用于创建新工作簿
from openpyxl import Workbook

# 说明:创建一个新的空工作簿
# Workbook() 函数创建一个新的 Excel 工作簿对象
wb = Workbook()

# 说明:获取默认工作表
# active 属性返回当前活动的工作表(通常是第一个工作表)
ws = wb.active

# 说明:设置工作表的名称
# title 属性可以读取或设置工作表的名称
ws.title = "销售数据"

# 说明:在工作表中写入数据
# 通过坐标(如 "A1")可以直接访问单元格并赋值
# A1 表示第一行第一列的单元格
ws["A1"] = "月份"
ws["B1"] = "收入"

# 说明:使用 append() 方法添加一行数据
# append() 方法在表的末尾添加一行数据
# 参数是一个列表,列表中的每个元素对应一列
ws.append(["一月", 1000])
ws.append(["二月", 1500])
ws.append(["三月", 1200])

# 说明:保存工作簿到文件
# save() 方法将工作簿保存到指定的文件路径
# 如果文件已存在,会被覆盖;如果不存在,会创建新文件
wb.save("quick_start.xlsx")

# 说明:打印成功消息
print("工作簿已创建:quick_start.xlsx")
print(f"工作表名称:{ws.title}")

4.2 读取工作簿 #

本代码块中使用的 OpenPyXL 方法:

方法 功能说明 常用参数 返回值
load_workbook() 加载已有的工作簿文件 filename:文件路径,read_only:是否只读(可选),data_only:是否只读取值(可选) Workbook 对象
.sheetnames 获取所有工作表的名称列表 无(属性) 字符串列表
.value 获取单元格的值 无(属性) 单元格的值
# -*- coding: utf-8 -*-
# 说明:快速体验 OpenPyXL - 读取工作簿

# 说明:导入 openpyxl 库
# 从 openpyxl 导入 load_workbook 函数,用于加载已有工作簿
from openpyxl import load_workbook

# 说明:加载已有的工作簿文件
# load_workbook() 函数从文件路径加载一个 Excel 工作簿
# 返回 Workbook 对象
wb = load_workbook("quick_start.xlsx")

# 说明:获取所有工作表的名称
# sheetnames 属性返回工作簿中所有工作表名称的列表
sheet_names = wb.sheetnames
print("所有工作表名称:", sheet_names)

# 说明:通过名称获取工作表
# 可以通过工作表名称访问特定的工作表
ws = wb["销售数据"]

# 说明:读取单元格的值
# 通过坐标访问单元格,然后使用 value 属性获取单元格的值
month = ws["A1"].value
revenue = ws["B1"].value
print(f"\n标题行:{month} | {revenue}")

# 说明:遍历并读取多行数据
# 可以通过坐标范围(如 "A2:B4")访问多个单元格
print("\n数据内容:")
for row in ws["A2:B4"]:
    # 说明:row 是一个包含多个 Cell 对象的元组
    # row[0] 是第一列的单元格,row[1] 是第二列的单元格
    month_value = row[0].value
    revenue_value = row[1].value
    print(f"  {month_value}:{revenue_value}")

# 说明:关闭工作簿(可选,但推荐)
# 如果不再需要访问工作簿,可以关闭它以释放资源
wb.close()

5. 工作簿与工作表管理 #

在实际应用中,你可能需要创建多个工作表、复制工作表或删除工作表。本节介绍如何管理工作表。

5.1 创建和删除工作表 #

本代码块中使用的 OpenPyXL 方法:

方法 功能说明 常用参数 返回值
.create_sheet() 创建新工作表 title:工作表名称,index:插入位置(可选,0 表示最前面) Worksheet 对象
.remove() 删除工作表 worksheet:要删除的工作表对象 无
# -*- coding: utf-8 -*-
# 说明:演示如何创建和删除工作表

# 说明:导入 openpyxl 库
from openpyxl import Workbook

# 说明:创建一个新的工作簿
wb = Workbook()

# 说明:获取默认工作表
# active 属性返回当前活动的工作表
ws_main = wb.active

# 说明:设置默认工作表的名称
ws_main.title = "主表"

# 说明:在末尾创建新工作表
# create_sheet() 方法创建新的工作表
# 如果只提供 title 参数,新工作表会被添加到末尾
ws_summary = wb.create_sheet("汇总表")

# 说明:在最前面插入新工作表
# create_sheet() 的 index 参数指定插入位置
# index=0 表示插入到最前面
ws_first = wb.create_sheet("报表头", 0)

# 说明:在新工作表中写入数据
# 可以在新创建的工作表中直接写入数据
ws_summary["A1"] = "这是汇总表"
ws_first["A1"] = "这是报表头"

# 说明:打印所有工作表名称
# sheetnames 属性返回所有工作表名称的列表
print("创建后的工作表:", wb.sheetnames)

# 说明:删除工作表
# remove() 方法删除指定的工作表
# 参数是要删除的工作表对象
wb.remove(ws_summary)

# 说明:打印删除后的工作表名称
print("删除后的工作表:", wb.sheetnames)

# 说明:保存工作簿
wb.save("sheets_manage.xlsx")
print("\n工作簿已保存:sheets_manage.xlsx")

5.2 复制工作表 #

本代码块中使用的 OpenPyXL 方法:

方法 功能说明 常用参数 返回值
.copy_worksheet() 复制工作表 worksheet:要复制的工作表对象 新创建的 Worksheet 对象
# -*- coding: utf-8 -*-
# 说明:演示如何复制工作表

# 说明:导入 openpyxl 库
from openpyxl import Workbook

# 说明:创建新工作簿
wb = Workbook()

# 说明:获取默认工作表
ws_main = wb.active

# 说明:设置工作表名称
ws_main.title = "主表"

# 说明:在主表中写入一些数据
ws_main["A1"] = "姓名"
ws_main["A2"] = "张三"
ws_main["A3"] = "李四"

# 说明:复制工作表
# copy_worksheet() 方法复制指定的工作表
# 参数是要复制的工作表对象
# 返回新创建的工作表对象(包含所有数据和格式)
ws_copy = wb.copy_worksheet(ws_main)

# 说明:设置副本的名称
# 复制后的工作表需要设置新名称
ws_copy.title = "主表副本"

# 说明:在副本中修改数据(验证是独立的副本)
ws_copy["A2"] = "王五"

# 说明:打印所有工作表名称
print("所有工作表:", wb.sheetnames)

# 说明:验证主表和副本的数据不同
print(f"\n主表 A2 的值:{ws_main['A2'].value}")
print(f"副本 A2 的值:{ws_copy['A2'].value}")

# 说明:保存工作簿
wb.save("sheets_copy.xlsx")
print("\n工作簿已保存:sheets_copy.xlsx")

6. 单元格读写:多种方式访问单元格 #

OpenPyXL 提供了多种方式来访问和操作单元格。理解这些方法可以提高代码的可读性和灵活性。

6.1 通过坐标访问单元格 #

本代码块中使用的 OpenPyXL 方法:

方法/属性 功能说明 常用参数 返回值
ws[坐标] 通过坐标访问单元格 坐标:如 "A1" Cell 对象
.value 获取或设置单元格的值 无(属性),可直接赋值 单元格的值
.cell() 通过行号和列号访问单元格 row:行号(从 1 开始),column:列号(从 1 开始),value:值(可选) Cell 对象
# -*- coding: utf-8 -*-
# 说明:演示多种方式访问和操作单元格

# 说明:导入 openpyxl 库
from openpyxl import Workbook

# 说明:创建新工作簿
wb = Workbook()
ws = wb.active

# 说明:方法1:通过坐标字符串直接访问(最常用)
# 使用类似 "A1"、"B2" 这样的字符串坐标
# 这种方式最直观,类似于 Excel 中的单元格引用
ws["A1"] = "姓名"
ws["B1"] = "成绩"

# 说明:方法2:使用 cell() 方法通过行号和列号访问
# cell() 方法的第一个参数是行号(从 1 开始),第二个参数是列号(从 1 开始)
# 列号也可以用数字:1=A, 2=B, 3=C...
# 这种方式适合在循环中使用
ws.cell(row=2, column=1, value="张三")
ws.cell(row=2, column=2, value=95)

# 说明:方法3:先获取单元格对象,再设置值
# 可以先获取 Cell 对象,然后单独设置其 value 属性
cell_a3 = ws.cell(row=3, column=1)
cell_a3.value = "李四"
cell_b3 = ws["B3"]
cell_b3.value = 88

# 说明:读取单元格的值
# 使用 value 属性可以读取单元格的值
name_a2 = ws["A2"].value
score_b2 = ws["B2"].value
print(f"A2 单元格的值:{name_a2}")
print(f"B2 单元格的值:{score_b2}")

# 说明:保存工作簿
wb.save("cells_basic.xlsx")
print("\n工作簿已保存:cells_basic.xlsx")

6.2 批量添加数据 #

本代码块中使用的 OpenPyXL 方法:

方法 功能说明 常用参数 返回值
.append() 在工作表末尾添加一行数据 row:包含一行数据的列表或元组 无
# -*- coding: utf-8 -*-
# 说明:演示如何批量添加数据

# 说明:导入 openpyxl 库
from openpyxl import Workbook

# 说明:创建新工作簿
wb = Workbook()
ws = wb.active

# 说明:设置标题行
ws["A1"] = "姓名"
ws["B1"] = "成绩"
ws["C1"] = "等级"

# 说明:方法1:逐行添加数据
# append() 方法在表的末尾添加一行数据
# 参数是一个列表,列表中的每个元素对应一列
ws.append(["张三", 95, "优秀"])
ws.append(["李四", 88, "良好"])
ws.append(["王五", 76, "及格"])

# 说明:方法2:使用循环批量添加
# 如果你有一个包含多行数据的列表,可以使用循环逐行添加
students = [
    ["赵六", 92, "优秀"],
    ["钱七", 85, "良好"],
    ["孙八", 70, "及格"],
]

# 说明:遍历学生列表,逐行添加
for student in students:
    ws.append(student)

# 说明:读取所有数据
# 可以通过坐标范围访问多个单元格
print("所有学生数据:")
for row in ws["A1:C6"]:
    # 说明:row 是一个包含多个 Cell 对象的元组
    # 遍历每行的单元格并打印值
    row_values = [cell.value for cell in row]
    print("  ", row_values)

# 说明:保存工作簿
wb.save("cells_append.xlsx")
print("\n工作簿已保存:cells_append.xlsx")

6.3 遍历单元格 #

本代码块中使用的 OpenPyXL 方法:

方法/属性 功能说明 常用参数 返回值
ws[范围] 通过范围访问多个单元格 范围:如 "A1:C3" 包含 Cell 对象的元组的元组
.iter_rows() 遍历指定范围的行 min_row:最小行号,max_row:最大行号,min_col:最小列号,max_col:最大列号,values_only:是否只返回值(可选) 迭代器,返回行
.coordinate 获取单元格的坐标 无(属性) 字符串,如 "A1"
# -*- coding: utf-8 -*-
# 说明:演示如何遍历单元格

# 说明:导入 openpyxl 库
from openpyxl import Workbook

# 说明:创建新工作簿并写入测试数据
wb = Workbook()
ws = wb.active

# 说明:写入一些测试数据
ws.append(["姓名", "年龄", "城市"])
ws.append(["张三", 25, "北京"])
ws.append(["李四", 30, "上海"])
ws.append(["王五", 28, "广州"])

# 说明:方法1:通过坐标范围遍历
# 使用类似 "A1:C4" 的字符串指定范围
print("方法1:通过坐标范围遍历")
for row in ws["A1:C4"]:
    # 说明:row 是一个包含多个 Cell 对象的元组
    # 遍历每行的单元格
    row_values = []
    for cell in row:
        # 说明:coordinate 属性返回单元格的坐标(如 "A1")
        # value 属性返回单元格的值
        row_values.append(f"{cell.coordinate}:{cell.value}")
    print("  ", " | ".join(row_values))

# 说明:方法2:使用 iter_rows() 方法遍历
# iter_rows() 方法返回一个迭代器,可以遍历指定范围的行
# values_only=True 表示只返回值,不返回 Cell 对象
print("\n方法2:使用 iter_rows() 遍历(只返回值)")
for row in ws.iter_rows(min_row=1, max_row=4, min_col=1, max_col=3, values_only=True):
    # 说明:row 是一个包含值的元组(不再是 Cell 对象)
    print("  ", row)

# 说明:方法3:使用 iter_rows() 返回 Cell 对象
print("\n方法3:使用 iter_rows() 遍历(返回 Cell 对象)")
for row in ws.iter_rows(min_row=1, max_row=4, min_col=1, max_col=3):
    # 说明:row 是一个包含 Cell 对象的元组
    row_values = []
    for cell in row:
        # 说明:可以访问 Cell 对象的属性
        row_values.append(f"{cell.coordinate}={cell.value}")
    print("  ", " | ".join(row_values))

# 说明:保存工作簿
wb.save("cells_iterate.xlsx")
print("\n工作簿已保存:cells_iterate.xlsx")

7. 样式设置:美化工作表 #

OpenPyXL 支持丰富的样式设置,包括字体、颜色、对齐、边框等。本节介绍常用的样式设置。

7.1 字体和颜色 #

本代码块中使用的 OpenPyXL 方法:

方法 功能说明 常用参数 返回值
Font() 创建字体对象 name:字体名称,size:字体大小,bold:是否粗体,color:字体颜色(RGB 十六进制) Font 对象
PatternFill() 创建填充对象 fill_type:填充类型(如 "solid"),fgColor:前景色(RGB 十六进制) PatternFill 对象
.font 设置单元格的字体 无(属性),可赋值为 Font 对象 无
.fill 设置单元格的填充 无(属性),可赋值为 PatternFill 对象 无
# -*- coding: utf-8 -*-
# 说明:演示如何设置字体和颜色

# 说明:导入 openpyxl 库和相关样式类
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill

# 说明:创建新工作簿
wb = Workbook()
ws = wb.active

# 说明:写入标题行数据
ws.append(["姓名", "部门", "绩效"])
ws.append(["张三", "研发", "A"])
ws.append(["李四", "市场", "B"])
ws.append(["王五", "销售", "A"])

# 说明:创建字体对象
# Font() 函数创建字体对象,可以设置字体名称、大小、颜色、粗体等属性
# bold=True 表示粗体
# color="FFFFFF" 表示白色(RGB 十六进制颜色码,FFFFFF 表示白色)
title_font = Font(
    name="微软雅黑",    # 字体名称(Windows)
    size=12,           # 字体大小
    bold=True,         # 是否粗体
    color="FFFFFF"     # 字体颜色(白色)
)

# 说明:创建填充对象
# PatternFill() 函数创建填充对象,可以设置单元格的背景色
# fill_type="solid" 表示纯色填充
# fgColor="4F81BD" 表示蓝色背景(RGB 十六进制颜色码)
title_fill = PatternFill(
    fill_type="solid",
    fgColor="4F81BD"
)

# 说明:设置标题行的样式
# 遍历第一行的所有单元格
for cell in ws[1]:
    # 说明:font 属性设置单元格的字体
    cell.font = title_font
    # 说明:fill 属性设置单元格的填充(背景色)
    cell.fill = title_fill

# 说明:设置数据行的样式(示例:设置绩效为 A 的行)
# 遍历第 2 到 4 行
for row_num in range(2, 5):
    # 说明:获取绩效列(C 列)的单元格
    performance_cell = ws.cell(row=row_num, column=3)
    # 说明:如果绩效是 A,设置特殊样式
    if performance_cell.value == "A":
        # 说明:创建绿色填充
        green_fill = PatternFill(fill_type="solid", fgColor="C6EFCE")
        performance_cell.fill = green_fill
        # 说明:创建粗体字体
        bold_font = Font(bold=True)
        performance_cell.font = bold_font

# 说明:保存工作簿
wb.save("styled_font.xlsx")
print("工作簿已保存:styled_font.xlsx")
print("已设置标题行样式(蓝色背景、白色粗体)")
print("已设置绩效 A 的样式(绿色背景、粗体)")

7.2 对齐和边框 #

本代码块中使用的 OpenPyXL 方法:

方法 功能说明 常用参数 返回值
Alignment() 创建对齐对象 horizontal:水平对齐("left"、"center"、"right"),vertical:垂直对齐("top"、"center"、"bottom") Alignment 对象
Border() 创建边框对象 left、right、top、bottom:四个方向的边框线 Border 对象
Side() 创建边框线对象 style:边框样式("thin"、"medium"、"thick" 等) Side 对象
.alignment 设置单元格的对齐 无(属性),可赋值为 Alignment 对象 无
.border 设置单元格的边框 无(属性),可赋值为 Border 对象 无
# -*- coding: utf-8 -*-
# 说明:演示如何设置对齐和边框

# 说明:导入 openpyxl 库和相关样式类
from openpyxl import Workbook
from openpyxl.styles import Alignment, Border, Side

# 说明:创建新工作簿
wb = Workbook()
ws = wb.active

# 说明:写入数据
ws.append(["姓名", "年龄", "工资"])
ws.append(["张三", 25, 8000])
ws.append(["李四", 30, 12000])
ws.append(["王五", 28, 10000])

# 说明:创建对齐对象
# Alignment() 函数创建对齐对象
# horizontal="center" 表示水平居中
# vertical="center" 表示垂直居中
center_align = Alignment(
    horizontal="center",  # 水平对齐:left(左)、center(中)、right(右)
    vertical="center"     # 垂直对齐:top(上)、center(中)、bottom(下)
)

# 说明:创建边框线对象
# Side() 函数创建边框线对象
# style="thin" 表示细线(其他选项:medium、thick 等)
thin_side = Side(style="thin")

# 说明:创建边框对象
# Border() 函数创建边框对象
# 可以设置四个方向的边框线:left(左)、right(右)、top(上)、bottom(下)
thin_border = Border(
    left=thin_side,    # 左边框
    right=thin_side,   # 右边框
    top=thin_side,     # 上边框
    bottom=thin_side   # 下边框
)

# 说明:设置所有单元格的对齐和边框
# 遍历所有有数据的行(1 到 4 行)
for row_num in range(1, 5):
    # 说明:遍历每行的所有列(1 到 3 列)
    for col_num in range(1, 4):
        # 说明:获取单元格
        cell = ws.cell(row=row_num, column=col_num)
        # 说明:设置对齐
        cell.alignment = center_align
        # 说明:设置边框
        cell.border = thin_border

# 说明:保存工作簿
wb.save("styled_align_border.xlsx")
print("工作簿已保存:styled_align_border.xlsx")
print("已设置所有单元格居中对齐和细边框")

7.3 行高和列宽 #

本代码块中使用的 OpenPyXL 方法:

方法/属性 功能说明 常用参数 返回值
.column_dimensions 访问列尺寸对象 列字母(如 "A") ColumnDimension 对象
.row_dimensions 访问行尺寸对象 行号(如 1) RowDimension 对象
.width 设置列宽 无(属性),可直接赋值为数字 无
.height 设置行高 无(属性),可直接赋值为数字 无
# -*- coding: utf-8 -*-
# 说明:演示如何设置行高和列宽

# 说明:导入 openpyxl 库
from openpyxl import Workbook

# 说明:创建新工作簿
wb = Workbook()
ws = wb.active

# 说明:写入数据
ws.append(["姓名", "部门", "职位", "工资"])
ws.append(["张三", "研发部", "高级工程师", 15000])
ws.append(["李四", "市场部", "市场经理", 18000])
ws.append(["王五", "销售部", "销售总监", 20000])

# 说明:设置列宽
# column_dimensions[列字母] 访问指定列的尺寸对象
# width 属性设置列宽(数字表示字符宽度)
ws.column_dimensions["A"].width = 10  # A 列宽度为 10 个字符
ws.column_dimensions["B"].width = 12  # B 列宽度为 12 个字符
ws.column_dimensions["C"].width = 15  # C 列宽度为 15 个字符
ws.column_dimensions["D"].width = 10  # D 列宽度为 10 个字符

# 说明:设置行高
# row_dimensions[行号] 访问指定行的尺寸对象
# height 属性设置行高(数字表示磅值,约 72 磅 = 1 英寸)
ws.row_dimensions[1].height = 30  # 第一行(标题行)高度为 30 磅
ws.row_dimensions[2].height = 25  # 第二行高度为 25 磅
ws.row_dimensions[3].height = 25  # 第三行高度为 25 磅
ws.row_dimensions[4].height = 25  # 第四行高度为 25 磅

# 说明:批量设置列宽
# 可以使用循环批量设置多列的宽度
for col_letter in ["A", "B", "C", "D"]:
    # 说明:如果列宽小于 12,设置为 12
    if ws.column_dimensions[col_letter].width < 12:
        ws.column_dimensions[col_letter].width = 12

# 说明:保存工作簿
wb.save("styled_dimensions.xlsx")
print("工作簿已保存:styled_dimensions.xlsx")
print("已设置列宽和行高")

8. 公式计算 #

OpenPyXL 支持在单元格中写入 Excel 公式。当你在 Excel 中打开文件时,公式会自动计算。

8.1 基本公式 #

本代码块中使用的 OpenPyXL 方法:

方法 功能说明 常用参数 返回值
ws[坐标] 访问单元格 坐标:如 "A1" Cell 对象
.value 设置单元格的值(可以是公式字符串) 无(属性),可直接赋值 无
# -*- coding: utf-8 -*-
# 说明:演示如何在工作表中写入公式

# 说明:导入 openpyxl 库
from openpyxl import Workbook

# 说明:创建新工作簿
wb = Workbook()
ws = wb.active

# 说明:写入标题行
ws.append(["月份", "产品A", "产品B", "产品C", "总计"])

# 说明:写入数据行
# 第一行数据
ws.append(["一月", 1000, 800, 600])
# 说明:在总计列(E 列)写入公式
# 公式字符串以 "=" 开头,类似于 Excel 中的公式
# SUM(B2:D2) 表示对 B2 到 D2 的单元格求和
ws["E2"] = "=SUM(B2:D2)"

# 说明:第二行数据
ws.append(["二月", 1200, 950, 700])
ws["E3"] = "=SUM(B3:D3)"

# 说明:第三行数据
ws.append(["三月", 900, 1100, 800])
ws["E3"] = "=SUM(B3:D3)"

# 说明:在末尾添加平均行
# 使用 AVERAGE 函数计算平均值
ws.append(["平均值", "=AVERAGE(B2:B4)", "=AVERAGE(C2:C4)", "=AVERAGE(D2:D4)", "=AVERAGE(E2:E4)"])

# 说明:保存工作簿
wb.save("formula_basic.xlsx")
print("工作簿已保存:formula_basic.xlsx")
print("已写入公式:SUM(求和)和 AVERAGE(平均值)")
print("在 Excel 中打开文件时,公式会自动计算")

8.2 常用公式示例 #

本代码块中使用的 OpenPyXL 方法:

方法 功能说明 常用参数 返回值
.value 设置单元格的值(可以是公式字符串) 无(属性),可直接赋值 无
# -*- coding: utf-8 -*-
# 说明:演示更多常用公式

# 说明:导入 openpyxl 库
from openpyxl import Workbook

# 说明:创建新工作簿
wb = Workbook()
ws = wb.active

# 说明:写入学生成绩数据
ws.append(["姓名", "语文", "数学", "英语", "总分", "平均分", "最高分", "最低分"])
ws.append(["张三", 85, 90, 88, None, None, None, None])
ws.append(["李四", 92, 95, 90, None, None, None, None])
ws.append(["王五", 78, 85, 80, None, None, None, None])

# 说明:为每行添加公式
# 遍历第 2 到 4 行(数据行)
for row_num in range(2, 5):
    # 说明:计算总分(SUM 函数)
    ws.cell(row=row_num, column=5).value = f"=SUM(B{row_num}:D{row_num})"

    # 说明:计算平均分(AVERAGE 函数)
    ws.cell(row=row_num, column=6).value = f"=AVERAGE(B{row_num}:D{row_num})"

    # 说明:计算最高分(MAX 函数)
    ws.cell(row=row_num, column=7).value = f"=MAX(B{row_num}:D{row_num})"

    # 说明:计算最低分(MIN 函数)
    ws.cell(row=row_num, column=8).value = f"=MIN(B{row_num}:D{row_num})"

# 说明:在最后一行添加统计信息
ws.append(["统计", "=AVERAGE(B2:B4)", "=AVERAGE(C2:C4)", "=AVERAGE(D2:D4)", "=SUM(E2:E4)", "=AVERAGE(F2:F4)", None, None])

# 说明:保存工作簿
wb.save("formula_advanced.xlsx")
print("工作簿已保存:formula_advanced.xlsx")
print("已写入多种公式:")
print("  - SUM:求和")
print("  - AVERAGE:平均值")
print("  - MAX:最大值")
print("  - MIN:最小值")

9. 读取大文件:优化性能 #

当处理大型 Excel 文件时,需要考虑性能问题。OpenPyXL 提供了只读模式和写入模式来优化性能。

9.1 只读模式读取 #

本代码块中使用的 OpenPyXL 方法:

方法 功能说明 常用参数 返回值
load_workbook() 加载工作簿 filename:文件路径,read_only:是否只读(True/False) Workbook 对象
.close() 关闭工作簿 无 无
.iter_rows() 遍历行 values_only:是否只返回值(True/False) 迭代器
# -*- coding: utf-8 -*-
# 说明:演示如何使用只读模式读取大文件

# 说明:导入 openpyxl 库
from openpyxl import Workbook, load_workbook

# 说明:先创建一个较大的测试文件
print("创建测试文件...")
wb_test = Workbook()
ws_test = wb_test.active

# 说明:写入标题行
ws_test.append(["ID", "姓名", "年龄", "城市"])

# 说明:写入大量测试数据(1000 行)
for i in range(1, 1001):
    ws_test.append([i, f"用户{i}", 20 + (i % 50), f"城市{i % 10}"])

# 说明:保存测试文件
wb_test.save("large_file.xlsx")
print("测试文件已创建:large_file.xlsx(1000 行数据)")

# 说明:方法1:使用只读模式读取(推荐用于大文件)
# load_workbook() 的 read_only=True 参数开启只读模式
# 只读模式会显著降低内存占用,提高读取速度
print("\n方法1:只读模式读取")
wb_readonly = load_workbook("large_file.xlsx", read_only=True)
ws_readonly = wb_readonly.active

# 说明:使用 iter_rows() 遍历行
# values_only=True 表示只返回值,不返回 Cell 对象,进一步减少内存占用
count = 0
for row in ws_readonly.iter_rows(values_only=True):
    count += 1
    # 说明:只读取前 5 行作为示例
    if count <= 5:
        print(f"  第 {count} 行:{row}")

    # 说明:如果只读模式,不能修改工作表
    # 只能读取数据

# 说明:关闭工作簿(只读模式必须手动关闭)
wb_readonly.close()
print(f"\n总共读取 {count} 行数据")

# 说明:方法2:普通模式读取(适用于小文件)
print("\n方法2:普通模式读取(前 5 行)")
wb_normal = load_workbook("large_file.xlsx")
ws_normal = wb_normal.active

# 说明:普通模式可以修改数据
for row_num in range(1, 6):
    row_values = []
    for col_num in range(1, 5):
        cell_value = ws_normal.cell(row=row_num, column=col_num).value
        row_values.append(cell_value)
    print(f"  第 {row_num} 行:{tuple(row_values)}")

# 说明:普通模式需要手动关闭(虽然 Python 垃圾回收会处理,但推荐手动关闭)
wb_normal.close()

print("\n性能建议:")
print("  - 大文件读取:使用 read_only=True")
print("  - 需要修改数据:使用普通模式")
print("  - 只读取值:使用 values_only=True")

10. 实战案例:销售报表生成器 #

下面是一个完整的实战案例,综合运用前面学到的知识,创建一个销售报表生成器。

本代码块中使用的 OpenPyXL 方法总结:

方法/属性 功能说明
Workbook() 创建工作簿
.active 获取活动工作表
.title 设置工作表名称
ws.append() 添加行数据
ws[坐标] 访问单元格
Font() 创建字体对象
PatternFill() 创建填充对象
Alignment() 创建对齐对象
.save() 保存工作簿
# -*- coding: utf-8 -*-
# 说明:实战案例 - 销售报表生成器
# 综合运用前面学到的所有知识,创建一个完整的销售报表

# 说明:导入所需的库
from datetime import datetime
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side

def build_sales_report(filename: str) -> None:
    """
    生成销售报表

    参数:
        filename (str): 输出文件名
    """
    # 说明:准备销售数据
    # 数据格式:(月份, 产品A销量, 产品B销量, 产品C销量)
    sales_data = [
        ("一月", 1000, 1500, 800),
        ("二月", 1200, 1600, 900),
        ("三月", 1100, 1700, 850),
        ("四月", 1300, 1800, 950),
        ("五月", 1250, 1750, 900),
    ]

    # 说明:创建新工作簿
    wb = Workbook()
    ws = wb.active
    ws.title = "销售报表"

    # 说明:设置标题行
    headers = ["月份", "产品A", "产品B", "产品C", "总计", "平均"]
    ws.append(headers)

    # 说明:创建样式对象
    # 标题行字体:白色、粗体
    header_font = Font(name="微软雅黑", size=12, bold=True, color="FFFFFF")
    # 标题行填充:深蓝色背景
    header_fill = PatternFill(fill_type="solid", fgColor="1F4E78")
    # 居中对齐
    center_align = Alignment(horizontal="center", vertical="center")
    # 细边框
    thin_border = Border(
        left=Side(style="thin"),
        right=Side(style="thin"),
        top=Side(style="thin"),
        bottom=Side(style="thin")
    )

    # 说明:设置标题行样式
    for cell in ws[1]:
        cell.font = header_font
        cell.fill = header_fill
        cell.alignment = center_align
        cell.border = thin_border

    # 说明:写入数据行并添加公式
    for idx, row_data in enumerate(sales_data, start=2):
        # 说明:写入月份和三个产品的销量
        ws.append([row_data[0], row_data[1], row_data[2], row_data[3], None, None])

        # 说明:添加总计公式(E 列)
        ws.cell(row=idx, column=5).value = f"=SUM(B{idx}:D{idx})"

        # 说明:添加平均公式(F 列)
        ws.cell(row=idx, column=6).value = f"=AVERAGE(B{idx}:D{idx})"

        # 说明:设置数据行样式
        for col_num in range(1, 7):
            cell = ws.cell(row=idx, column=col_num)
            cell.alignment = center_align
            cell.border = thin_border

    # 说明:添加总计行
    total_row = len(sales_data) + 2
    ws.cell(row=total_row, column=1).value = "总计"
    ws.cell(row=total_row, column=2).value = f"=SUM(B2:B{total_row-1})"
    ws.cell(row=total_row, column=3).value = f"=SUM(C2:C{total_row-1})"
    ws.cell(row=total_row, column=4).value = f"=SUM(D2:D{total_row-1})"
    ws.cell(row=total_row, column=5).value = f"=SUM(E2:E{total_row-1})"
    ws.cell(row=total_row, column=6).value = f"=AVERAGE(F2:F{total_row-1})"

    # 说明:设置总计行样式(突出显示)
    total_font = Font(bold=True)
    total_fill = PatternFill(fill_type="solid", fgColor="D9E1F2")
    for col_num in range(1, 7):
        cell = ws.cell(row=total_row, column=col_num)
        cell.font = total_font
        cell.fill = total_fill
        cell.alignment = center_align
        cell.border = thin_border

    # 说明:设置列宽
    ws.column_dimensions["A"].width = 12
    ws.column_dimensions["B"].width = 10
    ws.column_dimensions["C"].width = 10
    ws.column_dimensions["D"].width = 10
    ws.column_dimensions["E"].width = 10
    ws.column_dimensions["F"].width = 10

    # 说明:设置标题行高度
    ws.row_dimensions[1].height = 25

    # 说明:保存工作簿
    wb.save(filename)
    print(f"✓ 报表已生成:{filename}")


# 说明:主程序入口
if __name__ == "__main__":
    # 说明:生成带时间戳的文件名
    today = datetime.now().strftime("%Y%m%d_%H%M%S")
    filename = f"sales_report_{today}.xlsx"

    # 说明:调用函数生成报表
    build_sales_report(filename)

    print("\n报表包含:")
    print("  - 标题行(深蓝色背景、白色粗体)")
    print("  - 数据行(包含公式计算总计和平均)")
    print("  - 总计行(突出显示)")
    print("  - 样式美化(边框、对齐、列宽)")

11. 常见问题与排查 #

在使用 OpenPyXL 时,可能会遇到一些常见问题。本节提供解决方案。

11.1 文件损坏问题 #

问题:保存后的文件无法打开或提示损坏。

原因:通常是文件被其他程序占用,或者在写入过程中程序异常退出。

解决方案:

# -*- coding: utf-8 -*-
# 说明:演示如何避免文件损坏问题

# 说明:导入 openpyxl 库
from openpyxl import Workbook
import os

# 说明:方法1:使用 try-except 确保文件正确关闭
wb = Workbook()
ws = wb.active
ws["A1"] = "测试"

try:
    # 说明:保存文件
    wb.save("safe_save.xlsx")
    print("文件已保存:safe_save.xlsx")
except Exception as e:
    # 说明:如果保存失败,捕获异常
    print(f"保存失败:{e}")

# 说明:方法2:检查文件是否被占用
def is_file_locked(filepath: str) -> bool:
    """
    检查文件是否被占用

    参数:
        filepath (str): 文件路径

    返回:
        bool: 如果文件被占用返回 True,否则返回 False
    """
    if not os.path.exists(filepath):
        return False

    try:
        # 说明:尝试以写入模式打开文件
        with open(filepath, "r+b"):
            return False
    except IOError:
        # 说明:如果无法打开,说明文件被占用
        return True

# 说明:使用示例
filepath = "test_file.xlsx"
if is_file_locked(filepath):
    print(f"文件 {filepath} 被占用,请先关闭 Excel")
else:
    # 说明:文件未被占用,可以安全保存
    wb = Workbook()
    ws = wb.active
    ws["A1"] = "测试"
    wb.save(filepath)
    print("文件已安全保存")

11.2 中文字体显示问题 #

问题:设置的中文字体不生效或显示异常。

原因:字体名称在系统中不存在。

解决方案:

# -*- coding: utf-8 -*-
# 说明:演示如何正确设置中文字体

# 说明:导入 openpyxl 库
from openpyxl import Workbook
from openpyxl.styles import Font

# 说明:创建新工作簿
wb = Workbook()
ws = wb.active

# 说明:写入中文内容
ws["A1"] = "这是中文测试"
ws["A2"] = "Hello World"

# 说明:Windows 系统常用中文字体
# 如果字体不存在,OpenPyXL 会使用默认字体
windows_fonts = [
    "微软雅黑",      # Windows 默认中文字体
    "宋体",          # 传统中文字体
    "黑体",          # 粗体中文字体
]

# 说明:macOS 系统常用中文字体
macos_fonts = [
    "PingFang SC",   # macOS 默认中文字体
    "STSong",        # 宋体
    "STHeiti",       # 黑体
]

# 说明:尝试设置字体(根据系统选择)
# 在实际使用中,你需要根据运行环境选择合适的字体
try:
    # 说明:Windows 用户可以使用
    font = Font(name="微软雅黑", size=12)
except:
    # 说明:macOS 用户可以使用
    font = Font(name="PingFang SC", size=12)

# 说明:应用字体
ws["A1"].font = font

# 说明:保存文件
wb.save("font_test.xlsx")
print("文件已保存:font_test.xlsx")
print("提示:如果字体显示异常,请检查系统是否安装了该字体")

11.3 公式不计算问题 #

问题:写入的公式在 Excel 中不自动计算。

原因:OpenPyXL 只写入公式字符串,Excel 会在打开文件时自动计算。

解决方案:

# -*- coding: utf-8 -*-
# 说明:说明公式计算的问题和解决方案

# 说明:导入 openpyxl 库
from openpyxl import Workbook

# 说明:创建新工作簿
wb = Workbook()
ws = wb.active

# 说明:写入数据
ws.append(["数字1", "数字2", "求和"])
ws.append([10, 20, "=SUM(A2:B2)"])
ws.append([30, 40, "=SUM(A3:B3)"])

# 说明:保存文件
wb.save("formula_test.xlsx")

print("文件已保存:formula_test.xlsx")
print("\n重要说明:")
print("  - OpenPyXL 只写入公式字符串,不会计算结果")
print("  - 当你用 Excel 打开文件时,公式会自动计算")
print("  - 如果需要立即得到计算结果,可以在 Python 中手动计算:")

# 说明:如果需要立即得到计算结果,可以手动计算
result = 10 + 20
ws["C2"].value = result  # 直接写入计算结果而不是公式

print(f"  - 例如:10 + 20 = {result}")
print("  - 可以直接写入计算结果而不是公式")

11.4 性能优化建议 #

问题:处理大文件时速度慢或内存占用高。

解决方案:

# -*- coding: utf-8 -*-
# 说明:演示性能优化技巧

# 说明:导入 openpyxl 库
from openpyxl import Workbook, load_workbook

print("性能优化建议:")
print("\n1. 读取大文件时使用只读模式:")
print("   wb = load_workbook('large.xlsx', read_only=True)")

print("\n2. 遍历时使用 values_only=True:")
print("   for row in ws.iter_rows(values_only=True):")

print("\n3. 批量写入数据,避免逐个单元格操作:")
print("   # 好的方式:")
print("   ws.append([value1, value2, value3])")
print("   # 避免:")
print("   ws['A1'] = value1")
print("   ws['B1'] = value2")
print("   ws['C1'] = value3")

print("\n4. 完成后及时关闭工作簿:")
print("   wb.close()")

print("\n5. 如果只是读取值,使用 data_only=True:")
print("   wb = load_workbook('file.xlsx', data_only=True)")

# 说明:性能对比示例
print("\n性能对比示例:")

# 说明:慢的方式(逐个单元格写入)
print("\n慢的方式(逐个单元格):")
wb_slow = Workbook()
ws_slow = wb_slow.active
import time
start = time.time()
for i in range(1, 101):
    ws_slow.cell(row=i, column=1, value=i)
    ws_slow.cell(row=i, column=2, value=i*2)
slow_time = time.time() - start
print(f"  时间:{slow_time:.4f} 秒")

# 说明:快的方式(批量写入)
print("\n快的方式(批量写入):")
wb_fast = Workbook()
ws_fast = wb_fast.active
start = time.time()
for i in range(1, 101):
    ws_fast.append([i, i*2])
fast_time = time.time() - start
print(f"  时间:{fast_time:.4f} 秒")
print(f"  提速:{slow_time/fast_time:.2f} 倍")

12. 参考 #

  • OpenPyXL 官方文档
  • Excel 公式参考

访问验证

请输入访问令牌

Token不正确,请重新输入