上文介紹了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 XlsbWriterdef 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 Nonecurrent_sheet = 0current_row = 0sheet_data = []# 添加標題行到第一個 Sheetif headers:sheet_data.append(headers)for row in csv_reader:sheet_data.append(row)current_row += 1# 當達到最大行數時寫入當前 Sheet 并創建新 Sheetif current_row >= max_rows_per_sheet:# 寫入當前 Sheetsheet_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)}")# 準備下一個 Sheetcurrent_sheet += 1current_row = 0sheet_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.0C:\d\pypy>pypy3 -m pip install pyxlsbwriter
Successfully installed pyxlsbwriter-0.0.3C:\d\pypy>cd ..C:\d>timer64 pypy\pypy3 csv2xlsb.pyKernel 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,行數: 805701Kernel 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.xlsb2025/08/17 18:32 201,303,180 pypysheets.xlsb
2025/08/17 18:34 201,303,180 sheets.xlsbC:\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文件。