流式 xlsx 读取器,基于 quick-xml + zip 实现真正的流式解析
Project description
stream_xlsx
流式 xlsx 读取器,支持 Rust 库、CLI 工具和 Python 绑定。基于 quick-xml + zip 实现真正的流式解析,不一次性将整张表载入内存。
项目结构
sxlsx/ # CLI 工具(cargo build)
stream_xlsx/ # 纯 Rust 库(rlib)
stream_xlsx_py/ # pyo3 Python 绑定(maturin build)
特点
- 流式读取:逐 batch 产出 Polars DataFrame,100 万行 × 60 列(659 MB)只需 ~18–21 秒
- 双模式 Reader:
default(原始实现)与lm(低内存优化),CLI 通过--reader切换,Python 通过reader=参数切换 - 低内存:
lm模式峰值内存比default降低 ~35–50%,比 polars+calamine 降低 ~70% - 类型推断:边读边推断列类型(Int → Float → String),空值不参与推断
- 日期支持:读取
xl/styles.xml的cellXfs+ 自定义numFmt,自动识别日期列 - Shell 补全:内置 zsh / bash 自动补全生成
安装
CLI
cargo build --release
# 二进制位于 target/release/sxlsx
Python
cd stream_xlsx_py
maturin build --release
pip install target/wheels/stream_xlsx_py-*.whl
使用
CLI
# 导出为 CSV
sxlsx tf csv data.xlsx --output out.csv
# 导出为 parquet
sxlsx tf parquet data.xlsx # 省略output参数 默认原地址原名称生成
# 指定 sheet(按名称或索引)
sxlsx tf csv data.xlsx --sheet-name "Sheet1"
sxlsx tf csv data.xlsx --sheet-idx 0
# 统计行数(性能基准)
sxlsx test count data.xlsx
# 使用低内存模式(推荐大文件)
sxlsx --reader lm test count data.xlsx # 当前低内存模式已为默认 无需额外制定
# 生成测试文件:100 万行 × 60 列
sxlsx test test-file big.xlsx --rows 1000000 --col 60
# Shell 自动补全
sxlsx completion # 自动根据操作系统安装shell自动补全脚本
Python
import stream_xlsx_py as sx
# 默认 低内存模式
for df in sx.read_xlsx("data.xlsx", batch_size=10000):
print(df.shape)
# 全量读取
for df in sx.read_xlsx("data.xlsx"):
print(df.shape)
Benchmark
测试文件:test_100w_60c.xlsx(100 万行 × 60 列,sxlsx test test-file --rows 1000000 --col 60 生成,约 659 MB)
测试环境:macOS, Apple Silicon, release 构建。内存采样间隔 50 ms。
Python 环境对比
在 Python 进程中对比 stream_xlsx_py 流式遍历与 polars.read_excel 全量加载:
| 方案 | 时间 | 峰值内存 | 说明 |
|---|---|---|---|
| stream_xlsx_py (lm, bs=10k) | 19.87 s | 2,619 MB | 流式遍历,低内存模式 |
| stream_xlsx_py (default, bs=10k) | 19.55 s | 4,960 MB | 流式遍历,默认模式 |
| stream_xlsx_py (lm, bs=1M) | 20.24 s | 6,120 MB | 全量加载(单 batch) |
| stream_xlsx_py (default, bs=1M) | 19.37 s | 6,530 MB | 全量加载(单 batch) |
| polars + calamine | 25.05 s | 8,858 MB | pl.read_excel(engine="calamine") |
| polars + xlsx2csv | 95.16 s | 8,526 MB | pl.read_excel(engine="xlsx2csv") |
结论:
stream_xlsx_py比 polars+calamine 快 21%,内存 低 70%lm模式比default内存再降 47%,时间持平- 全量加载(bs=1M)时 stream_xlsx_py 与 polars 内存接近(仍小2G左右),但仍快 23%
上图可见 polars calamine 在 ~25 s 达到 ~8.9 GB 峰值,而 stream_xlsx_py 全程稳定在 2.6–6.5 GB;lm 模式上升最平缓,峰值最低。
CLI 环境对比(default vs lm)
逐 batch 遍历不保留中间结果(sxlsx test count):
| batch_size | default 时间 | lm 时间 | default 峰值 | lm 峰值 | 降幅 |
|---|---|---|---|---|---|
| 1,000 | 18.87 s | 18.03 s | 4,949 MB | 2,512 MB | –49% |
| 5,000 | 18.65 s | 18.00 s | 4,943 MB | 2,525 MB | –49% |
| 10,000 | 18.62 s | 18.11 s | 4,941 MB | 2,546 MB | –48% |
| 50,000 | 19.89 s | 18.04 s | 4,948 MB | 2,750 MB | –44% |
| 100,000 | 18.97 s | 18.04 s | 4,955 MB | 3,183 MB | –36% |
| 1,000,000 | 18.68 s | 18.42 s | 6,429 MB | 6,074 MB | –6% |
结论:
lm比default快 3–5%,内存降低 36–49%(流式场景)- batch_size 对时间影响极小,瓶颈在 XML 解析和 ZIP 解压
- 全量加载(bs=1M):lm 优势收窄(–6%),因为最终需要容纳 100 万行 × 60 列的 DataFrame,此时内存主要由 Polars 决定
上图展示了 12 个测试条件的内存曲线网格(2 readers × 6 batch sizes)。default(上行)在 ~7 s 出现明显峰值后骤降,lm(下行)曲线更平滑,全程线性上升后直接进入平稳期。全量加载(bs=1M,最右列)两者内存趋于一致,因为最终都需要容纳完整的 DataFrame。
batch=10000 时对比最清晰:default 在 7 s 达到 ~5 GB 峰值后骤降,lm 线性上升至 ~2.5 GB 后平稳,无 spikes。
为什么 lm 内存更低?
default 的 prepare() 阶段使用 read_to_end 一次性读取 sharedStrings.xml(约 2 GB),ZIP 解压缓冲 + XML 解析器缓冲共同推高内存到 ~5 GB;解析完成后缓冲释放,造成 50 ms 内骤降 ~2 GB。
lm 的 prepare() 改为 BufReader 直接流式解析,无中间 Vec<u8> 缓冲;sharedStrings 边读边解析到 Vec<Box<str>>,每元素比 Vec<String> 省 24 bytes 容量开销。内存曲线呈线性增长后直接进入平稳期。
推荐配置
| 场景 | 推荐参数 |
|---|---|
| 超大文件(>100 MB) | --reader lm --batchsize 10000 |
| 中等文件(10–100 MB) | --reader lm --batchsize 10000 |
| 小文件(<10 MB) | --batchsize 10000(default 即可) |
| 全量加载到单个 DataFrame | --batchsize 1000000(bs=1M 等效全量) |
小文件示例:
$ sxlsx --batchsize 10000 test count test_data.xlsx
11 145ms
构建
开发构建
# Rust 库 + CLI
cargo build
# 测试
cargo test --workspace
# Python wheel
cd stream_xlsx_py
maturin develop # 开发模式,直接链接到 .venv
maturin build --release
CI
项目已配置 Gitea Actions(.gitea/workflows/ci.yaml),每次 push/PR 自动运行:
cargo test --workspacecargo build --release(CLI artifact)maturin build --release(wheel artifact)
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file stream_xlsx_py-0.1.1-cp39-abi3-win_arm64.whl.
File metadata
- Download URL: stream_xlsx_py-0.1.1-cp39-abi3-win_arm64.whl
- Upload date:
- Size: 4.7 MB
- Tags: CPython 3.9+, Windows ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e6576cc53f48744eb0222c54a2a1290e3bb02c4150b7f75ceb88488c0a412f86
|
|
| MD5 |
c8a6e4cdd48e9ab22672be4974893dca
|
|
| BLAKE2b-256 |
e95e651952a0c34d988a1ea8b6dc7b7eaa0b4bd918de09b36a8dc9e8238c1f22
|
Provenance
The following attestation bundles were made for stream_xlsx_py-0.1.1-cp39-abi3-win_arm64.whl:
Publisher:
ci.yaml on LittleTomatoPotato/Stream-xlsx
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
stream_xlsx_py-0.1.1-cp39-abi3-win_arm64.whl -
Subject digest:
e6576cc53f48744eb0222c54a2a1290e3bb02c4150b7f75ceb88488c0a412f86 - Sigstore transparency entry: 1654257551
- Sigstore integration time:
-
Permalink:
LittleTomatoPotato/Stream-xlsx@4ff80f02e7fdb146efede2628feb4d90df4920a1 -
Branch / Tag:
refs/tags/v0.1.8 - Owner: https://github.com/LittleTomatoPotato
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yaml@4ff80f02e7fdb146efede2628feb4d90df4920a1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file stream_xlsx_py-0.1.1-cp39-abi3-win_amd64.whl.
File metadata
- Download URL: stream_xlsx_py-0.1.1-cp39-abi3-win_amd64.whl
- Upload date:
- Size: 5.3 MB
- Tags: CPython 3.9+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
75b10e5cddaecdf9f74ca127b1eec50572e393f0df2ba9f4b8ec0de9954b5a82
|
|
| MD5 |
60b04cd38244183771b04b4d4221647e
|
|
| BLAKE2b-256 |
37bfeade10e9229c459b2dbfffb7a0135cfa52eee05a3e78ad953698665182f2
|
Provenance
The following attestation bundles were made for stream_xlsx_py-0.1.1-cp39-abi3-win_amd64.whl:
Publisher:
ci.yaml on LittleTomatoPotato/Stream-xlsx
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
stream_xlsx_py-0.1.1-cp39-abi3-win_amd64.whl -
Subject digest:
75b10e5cddaecdf9f74ca127b1eec50572e393f0df2ba9f4b8ec0de9954b5a82 - Sigstore transparency entry: 1654257383
- Sigstore integration time:
-
Permalink:
LittleTomatoPotato/Stream-xlsx@4ff80f02e7fdb146efede2628feb4d90df4920a1 -
Branch / Tag:
refs/tags/v0.1.8 - Owner: https://github.com/LittleTomatoPotato
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yaml@4ff80f02e7fdb146efede2628feb4d90df4920a1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file stream_xlsx_py-0.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: stream_xlsx_py-0.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 5.8 MB
- Tags: CPython 3.9+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
47964e5bda21ed0ac9c961243620ee8d91b9bedad59f46be6448176d8a321a00
|
|
| MD5 |
c9c1fd3783cd931ece0b0c76f4f3fb47
|
|
| BLAKE2b-256 |
bff954234349db1f7b893f5ecd51cb0a355d24d40d42c9c514c5fe7e7858c194
|
Provenance
The following attestation bundles were made for stream_xlsx_py-0.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
ci.yaml on LittleTomatoPotato/Stream-xlsx
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
stream_xlsx_py-0.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
47964e5bda21ed0ac9c961243620ee8d91b9bedad59f46be6448176d8a321a00 - Sigstore transparency entry: 1654256635
- Sigstore integration time:
-
Permalink:
LittleTomatoPotato/Stream-xlsx@4ff80f02e7fdb146efede2628feb4d90df4920a1 -
Branch / Tag:
refs/tags/v0.1.8 - Owner: https://github.com/LittleTomatoPotato
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yaml@4ff80f02e7fdb146efede2628feb4d90df4920a1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file stream_xlsx_py-0.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: stream_xlsx_py-0.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 5.5 MB
- Tags: CPython 3.9+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3f6c1daeb13dec9fa7c0ceaa9450df9210e686064140728563ed59f962cdc6f8
|
|
| MD5 |
916220f0206125ec079e29600dfe5efb
|
|
| BLAKE2b-256 |
d16cf912f35ab44718b903f0bf1d5048f731c4c12093c20eedcd4a8155ca78df
|
Provenance
The following attestation bundles were made for stream_xlsx_py-0.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
ci.yaml on LittleTomatoPotato/Stream-xlsx
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
stream_xlsx_py-0.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
3f6c1daeb13dec9fa7c0ceaa9450df9210e686064140728563ed59f962cdc6f8 - Sigstore transparency entry: 1654256412
- Sigstore integration time:
-
Permalink:
LittleTomatoPotato/Stream-xlsx@4ff80f02e7fdb146efede2628feb4d90df4920a1 -
Branch / Tag:
refs/tags/v0.1.8 - Owner: https://github.com/LittleTomatoPotato
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yaml@4ff80f02e7fdb146efede2628feb4d90df4920a1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file stream_xlsx_py-0.1.1-cp39-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: stream_xlsx_py-0.1.1-cp39-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 5.0 MB
- Tags: CPython 3.9+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e0deb4836f1063d676ea27b2e39fd157f2f218c69e8787b36a56db2914762c6b
|
|
| MD5 |
f9c72d98d29fe3e432e1f308482b5177
|
|
| BLAKE2b-256 |
bd05e1ef91424f2634148e95bfbc6ed6dbdec2210a484d980ccb8b14a6b8a20f
|
Provenance
The following attestation bundles were made for stream_xlsx_py-0.1.1-cp39-abi3-macosx_11_0_arm64.whl:
Publisher:
ci.yaml on LittleTomatoPotato/Stream-xlsx
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
stream_xlsx_py-0.1.1-cp39-abi3-macosx_11_0_arm64.whl -
Subject digest:
e0deb4836f1063d676ea27b2e39fd157f2f218c69e8787b36a56db2914762c6b - Sigstore transparency entry: 1654256941
- Sigstore integration time:
-
Permalink:
LittleTomatoPotato/Stream-xlsx@4ff80f02e7fdb146efede2628feb4d90df4920a1 -
Branch / Tag:
refs/tags/v0.1.8 - Owner: https://github.com/LittleTomatoPotato
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yaml@4ff80f02e7fdb146efede2628feb4d90df4920a1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file stream_xlsx_py-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: stream_xlsx_py-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 5.3 MB
- Tags: CPython 3.9+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c4be82295673d5f4ae87bab4c51a3495d694e29debb300af7b562b8694770804
|
|
| MD5 |
4dd088c78d54a4f86d9e4b010e9d525c
|
|
| BLAKE2b-256 |
b4aa3f635c2a4c52fb13e2c0e6db6f16fd128f38283ce1aef89d023fbc157964
|
Provenance
The following attestation bundles were made for stream_xlsx_py-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl:
Publisher:
ci.yaml on LittleTomatoPotato/Stream-xlsx
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
stream_xlsx_py-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl -
Subject digest:
c4be82295673d5f4ae87bab4c51a3495d694e29debb300af7b562b8694770804 - Sigstore transparency entry: 1654257196
- Sigstore integration time:
-
Permalink:
LittleTomatoPotato/Stream-xlsx@4ff80f02e7fdb146efede2628feb4d90df4920a1 -
Branch / Tag:
refs/tags/v0.1.8 - Owner: https://github.com/LittleTomatoPotato
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yaml@4ff80f02e7fdb146efede2628feb4d90df4920a1 -
Trigger Event:
push
-
Statement type: