上文介绍了python通过DuckDB和pyxlsbwriter模块生成xlsb文件,因为python是解释执行,它的速度有点慢,pypy是另一种python解释器,它使用即时编译(JIT)技术来提高执行速度。
因为DuckDB与pypy不兼容,所以让DeepSeek帮助编写了不依赖DuckDB和pandas,直接使用python csv模块将csv文件内容写入多sheet的xlsb文件的程序。
源代码csv2xlsb.py如下:
import csv
import math
from pyxlsbwriter import XlsbWriter
def csv_to_xlsb(
csv_file,
output_file,
sheet_prefix="Sheet",
max_rows_per_sheet=1048575, # XLSB 单 Sheet 最大行数
compression_level=6,
has_header=True
):
"""
将大型 CSV 文件分 Sheet 写入 XLSB 文件
参数:
csv_file (str): 输入 CSV 文件路径
output_file (str): 输出 XLSB 文件路径
sheet_prefix (str): Sheet 名称前缀
max_rows_per_sheet (int): 每个 Sheet 最大行数
compression_level (int): 压缩级别(0-9)
has_header (bool): CSV 是否包含标题行
"""
# 首先计算总行数(为了确定需要的 Sheet 数量)
with open(csv_file, 'r', newline='', encoding='utf-8') as f:
total_rows = sum(1 for _ in csv.reader(f)) - (1 if has_header else 0)
num_sheets = math.ceil(total_rows / max_rows_per_sheet)
print(f"CSV 文件共有 {total_rows} 行数据,将分成 {num_sheets} 个 Sheet 写入")
with XlsbWriter(output_file, compressionLevel=compression_level) as writer:
with open(csv_file, 'r', newline='', encoding='utf-8') as f:
csv_reader = csv.reader(f)
# 读取标题行(如果有)
headers = next(csv_reader) if has_header else None
current_sheet = 0
current_row = 0
sheet_data = []
# 添加标题行到第一个 Sheet
if headers:
sheet_data.append(headers)
for row in csv_reader:
sheet_data.append(row)
current_row += 1
# 当达到最大行数时写入当前 Sheet 并创建新 Sheet
if current_row >= max_rows_per_sheet:
# 写入当前 Sheet
sheet_name = f"{sheet_prefix}_{current_sheet + 1}"
writer.add_sheet(sheet_name)
writer.write_sheet(sheet_data)
print(f"已写入 Sheet: {sheet_name},行数: {len(sheet_data)}")
# 准备下一个 Sheet
current_sheet += 1
current_row = 0
sheet_data = []
if headers: # 新 Sheet 也包含标题行
sheet_data.append(headers)
# 写入最后一个 Sheet(可能未达到最大行数)
if sheet_data:
sheet_name = f"{sheet_prefix}_{current_sheet + 1}"
writer.add_sheet(sheet_name)
writer.write_sheet(sheet_data)
print(f"已写入 Sheet: {sheet_name},行数: {len(sheet_data)}")
if __name__ == "__main__":
# 示例用法
csv_to_xlsb(
csv_file="5m Sales Records.csv",
output_file="sheets.xlsb",
sheet_prefix="Data",
max_rows_per_sheet=1048575, # 每个 Sheet 100 万行
compression_level=6,
has_header=True
)
下面是在pypy中安装pyxlsbwriter并执行的步骤
C:\d\pypy>pypy3 -m ensurepip
Successfully installed pip-24.0 setuptools-65.5.0
C:\d\pypy>pypy3 -m pip install pyxlsbwriter
Successfully installed pyxlsbwriter-0.0.3
C:\d\pypy>cd ..
C:\d>timer64 pypy\pypy3 csv2xlsb.py
Kernel Time = 1.750 = 2%
User Time = 58.546 = 97%
Process Time = 60.296 = 100% Virtual Memory = 3858 MB
Global Time = 60.271 = 100% Physical Memory = 3828 MB
我把第一步生成的sheets.xlsb文件改名为pypysheets.xlsb,以便比较。再用python执行同样的代码。
C:\d>move sheets.xlsb pypysheets.xlsb
移动了 1 个文件。
C:\d>timer64 python csv2xlsb.py
CSV 文件共有 5000000 行数据,将分成 5 个 Sheet 写入
已写入 Sheet: Data_1,行数: 1048576
已写入 Sheet: Data_2,行数: 1048576
已写入 Sheet: Data_3,行数: 1048576
已写入 Sheet: Data_4,行数: 1048576
已写入 Sheet: Data_5,行数: 805701
Kernel Time = 1.640 = 1%
User Time = 85.218 = 97%
Process Time = 86.859 = 99% Virtual Memory = 4728 MB
Global Time = 87.267 = 100% Physical Memory = 4724 MB
可见pypy3执行时间比python缩短了三分之一。再比较两个生成的文件,大小完全一致,再用FC命令比较,发现还是存在差异的。
C:\d>dir *sheets.xlsb
2025/08/17 18:32 201,303,180 pypysheets.xlsb
2025/08/17 18:34 201,303,180 sheets.xlsb
C:\d>fc /b sheets.xlsb pypysheets.xlsb
正在比较文件 sheets.xlsb 和 PYPYSHEETS.XLSB
024E15D8: 37 F5
024E15D9: 94 93
024E16D0: 37 F5
024E16D1: 94 93
...
0BFFA380: 57 0A
0BFFA3BD: 57 0A
0BFFA3F8: 57 0A
那pypy生成的文件到底对不对,能不能用,还是用rust_sheet插件来读取,比较如下:
先读取用python生成的sheets.xlsb
D create table xlsb as from read_sheet('sheets.xlsb',header=1,sheet_name='Data_1')
union all from read_sheet('sheets.xlsb',header=1,sheet_name='Data_2')
union all from read_sheet('sheets.xlsb',header=1,sheet_name='Data_3')
union all from read_sheet('sheets.xlsb',header=1,sheet_name='Data_4')
union all from read_sheet('sheets.xlsb',header=1,sheet_name='Data_5');
100% ▕████████████████████████████████████████████████████████████▏
Run Time (s): real 47.218 user 52.890625 sys 2.437500
D summarize xlsb;
┌────────────────┬─────────────┬─────────────┬────────────────────┬───┬───────┬───────┬─────────┬─────────────────┐
│ column_name │ column_type │ min │ max │ … │ q50 │ q75 │ count │ null_percentage │
│ varchar │ varchar │ varchar │ varchar │ │ int32 │ int32 │ int64 │ decimal(9,2) │
├────────────────┼─────────────┼─────────────┼────────────────────┼───┼───────┼───────┼─────────┼─────────────────┤
│ Region │ VARCHAR │ Asia │ Sub-Saharan Africa │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Country │ VARCHAR │ Afghanistan │ Zimbabwe │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Item Type │ VARCHAR │ Baby Food │ Vegetables │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Sales Channel │ VARCHAR │ Offline │ Online │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Order Priority │ VARCHAR │ C │ M │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Order Date │ VARCHAR │ 1/1/2010 │ 9/9/2020 │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Order ID │ VARCHAR │ 100000321 │ 999999892 │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Ship Date │ VARCHAR │ 1/1/2010 │ 9/9/2020 │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Units Sold │ VARCHAR │ 1 │ 9999 │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Unit Price │ VARCHAR │ 109.28 │ 9.33 │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Unit Cost │ VARCHAR │ 117.11 │ 97.44 │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Total Revenue │ VARCHAR │ 1000003.46 │ 999931.76 │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Total Cost │ VARCHAR │ 1000.23 │ 999979.98 │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Total Profit │ VARCHAR │ 100.24 │ 99997.92 │ … │ NULL │ NULL │ 5000000 │ 0.00 │
├────────────────┴─────────────┴─────────────┴────────────────────┴───┴───────┴───────┴─────────┴─────────────────┤
│ 14 rows 12 columns (8 shown) │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
Run Time (s): real 0.238 user 2.031250 sys 0.140625
再读取用pypy生成, 改名后的pypysheets.xlsb
D create table xlsb as from read_sheet('pypysheets.xlsb',header=1,sheet_name='Data_1')
union all from read_sheet('pypysheets.xlsb',header=1,sheet_name='Data_2')
union all from read_sheet('pypysheets.xlsb',header=1,sheet_name='Data_3')
union all from read_sheet('pypysheets.xlsb',header=1,sheet_name='Data_4')
union all from read_sheet('pypysheets.xlsb',header=1,sheet_name='Data_5');
100% ▕████████████████████████████████████████████████████████████▏
Run Time (s): real 45.734 user 43.078125 sys 2.531250
D summarize xlsb;
┌────────────────┬─────────────┬─────────────┬────────────────────┬───┬───────┬───────┬─────────┬─────────────────┐
│ column_name │ column_type │ min │ max │ … │ q50 │ q75 │ count │ null_percentage │
│ varchar │ varchar │ varchar │ varchar │ │ int32 │ int32 │ int64 │ decimal(9,2) │
├────────────────┼─────────────┼─────────────┼────────────────────┼───┼───────┼───────┼─────────┼─────────────────┤
│ Region │ VARCHAR │ Asia │ Sub-Saharan Africa │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Country │ VARCHAR │ Afghanistan │ Zimbabwe │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Item Type │ VARCHAR │ Baby Food │ Vegetables │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Sales Channel │ VARCHAR │ Offline │ Online │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Order Priority │ VARCHAR │ C │ M │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Order Date │ VARCHAR │ 1/1/2010 │ 9/9/2020 │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Order ID │ VARCHAR │ 100000321 │ 999999892 │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Ship Date │ VARCHAR │ 1/1/2010 │ 9/9/2020 │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Units Sold │ VARCHAR │ 1 │ 9999 │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Unit Price │ VARCHAR │ 109.28 │ 9.33 │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Unit Cost │ VARCHAR │ 117.11 │ 97.44 │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Total Revenue │ VARCHAR │ 1000003.46 │ 999931.76 │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Total Cost │ VARCHAR │ 1000.23 │ 999979.98 │ … │ NULL │ NULL │ 5000000 │ 0.00 │
│ Total Profit │ VARCHAR │ 100.24 │ 99997.92 │ … │ NULL │ NULL │ 5000000 │ 0.00 │
├────────────────┴─────────────┴─────────────┴────────────────────┴───┴───────┴───────┴─────────┴─────────────────┤
│ 14 rows 12 columns (8 shown) │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
Run Time (s): real 0.240 user 1.843750 sys 0.343750
读取时间基本一致,内容也一致。
所以,可以放心利用pypy加速pyxlsbwriter生成xlsb文件。