Skip to main content

流式 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 秒
  • 双模式 Readerdefault(原始实现)与 lm(低内存优化),CLI 通过 --reader 切换,Python 通过 reader= 参数切换
  • 低内存lm 模式峰值内存比 default 降低 ~35–50%,比 polars+calamine 降低 ~70%
  • 类型推断:边读边推断列类型(Int → Float → String),空值不参与推断
  • 日期支持:读取 xl/styles.xmlcellXfs + 自定义 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%

Python 环境内存曲线

上图可见 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%

结论

  • lmdefault 快 3–5%,内存降低 36–49%(流式场景)
  • batch_size 对时间影响极小,瓶颈在 XML 解析和 ZIP 解压
  • 全量加载(bs=1M):lm 优势收窄(–6%),因为最终需要容纳 100 万行 × 60 列的 DataFrame,此时内存主要由 Polars 决定

CLI 全条件内存网格

上图展示了 12 个测试条件的内存曲线网格(2 readers × 6 batch sizes)。default(上行)在 ~7 s 出现明显峰值后骤降,lm(下行)曲线更平滑,全程线性上升后直接进入平稳期。全量加载(bs=1M,最右列)两者内存趋于一致,因为最终都需要容纳完整的 DataFrame。

CLI batch=10000 对比

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 自动运行:

  1. cargo test --workspace
  2. cargo build --release(CLI artifact)
  3. 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

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

stream_xlsx_py-0.1.1-cp39-abi3-win_arm64.whl (4.7 MB view details)

Uploaded CPython 3.9+Windows ARM64

stream_xlsx_py-0.1.1-cp39-abi3-win_amd64.whl (5.3 MB view details)

Uploaded CPython 3.9+Windows x86-64

stream_xlsx_py-0.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (5.8 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ x86-64

stream_xlsx_py-0.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (5.5 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ ARM64

stream_xlsx_py-0.1.1-cp39-abi3-macosx_11_0_arm64.whl (5.0 MB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

stream_xlsx_py-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl (5.3 MB view details)

Uploaded CPython 3.9+macOS 10.12+ x86-64

File details

Details for the file stream_xlsx_py-0.1.1-cp39-abi3-win_arm64.whl.

File metadata

File hashes

Hashes for stream_xlsx_py-0.1.1-cp39-abi3-win_arm64.whl
Algorithm Hash digest
SHA256 e6576cc53f48744eb0222c54a2a1290e3bb02c4150b7f75ceb88488c0a412f86
MD5 c8a6e4cdd48e9ab22672be4974893dca
BLAKE2b-256 e95e651952a0c34d988a1ea8b6dc7b7eaa0b4bd918de09b36a8dc9e8238c1f22

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file stream_xlsx_py-0.1.1-cp39-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for stream_xlsx_py-0.1.1-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 75b10e5cddaecdf9f74ca127b1eec50572e393f0df2ba9f4b8ec0de9954b5a82
MD5 60b04cd38244183771b04b4d4221647e
BLAKE2b-256 37bfeade10e9229c459b2dbfffb7a0135cfa52eee05a3e78ad953698665182f2

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

File hashes

Hashes for stream_xlsx_py-0.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 47964e5bda21ed0ac9c961243620ee8d91b9bedad59f46be6448176d8a321a00
MD5 c9c1fd3783cd931ece0b0c76f4f3fb47
BLAKE2b-256 bff954234349db1f7b893f5ecd51cb0a355d24d40d42c9c514c5fe7e7858c194

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file stream_xlsx_py-0.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for stream_xlsx_py-0.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 3f6c1daeb13dec9fa7c0ceaa9450df9210e686064140728563ed59f962cdc6f8
MD5 916220f0206125ec079e29600dfe5efb
BLAKE2b-256 d16cf912f35ab44718b903f0bf1d5048f731c4c12093c20eedcd4a8155ca78df

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file stream_xlsx_py-0.1.1-cp39-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for stream_xlsx_py-0.1.1-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 e0deb4836f1063d676ea27b2e39fd157f2f218c69e8787b36a56db2914762c6b
MD5 f9c72d98d29fe3e432e1f308482b5177
BLAKE2b-256 bd05e1ef91424f2634148e95bfbc6ed6dbdec2210a484d980ccb8b14a6b8a20f

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file stream_xlsx_py-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for stream_xlsx_py-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 c4be82295673d5f4ae87bab4c51a3495d694e29debb300af7b562b8694770804
MD5 4dd088c78d54a4f86d9e4b010e9d525c
BLAKE2b-256 b4aa3f635c2a4c52fb13e2c0e6db6f16fd128f38283ce1aef89d023fbc157964

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page