Rust Office 库 — 快速上手
office_oxide 是一个纯 Rust crate,用于解析、转换和编辑 Office 文档:DOCX、XLSX、PPTX,以及旧版二进制格式 DOC、XLS、PPT。一个 crate、统一的 Document 句柄、零原生依赖。
安装
[dependencies]
office_oxide = "0.1.0"
可选功能开关(feature):
office_oxide = { version = "0.1.0", features = ["mmap"] } # 大文件内存映射打开
office_oxide = { version = "0.1.0", features = ["parallel"] } # 基于 rayon 的并行解析
读取文档
use office_oxide::Document;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let doc = Document::open("report.docx")?;
println!("{}", doc.plain_text());
Ok(())
}
或一次性辅助函数:
let text = office_oxide::extract_text("report.docx")?;
核心 API
Document 句柄对所有格式行为一致 — 通过扩展名识别,再用魔术字节复核。
use office_oxide::{Document, DocumentFormat};
let doc = Document::open("file.xlsx")?;
assert_eq!(doc.format(), DocumentFormat::Xlsx);
let plain = doc.plain_text();
let md = doc.to_markdown();
let html = doc.to_html();
let ir = doc.to_ir(); // 与格式无关的 IR
doc.save_as("file.docx")?; // 旧版格式 → OOXML 也可以
Document::open 接受 AsRef<Path>;Document::from_reader 接受 Read + Seek + Send + 'static,并需要显式 DocumentFormat。
模块级快捷函数:
let text = office_oxide::extract_text("file.docx")?;
let md = office_oxide::to_markdown("file.pptx")?;
let html = office_oxide::to_html("file.xlsx")?;
按格式访问
需要工作表、幻灯片、单元格等格式特有数据时,解包内部文档:
if let Some(xlsx) = doc.as_xlsx() {
for sheet in xlsx.sheets() {
println!("sheet: {}", sheet.name());
}
}
as_docx、as_pptx、as_doc、as_xls、as_ppt 模式相同。
编辑
EditableDocument 执行读—改—写流程,并保留所有未修改的 OPC 部件(图片、图表、样式、关系)。仅支持 DOCX、XLSX、PPTX。
use office_oxide::edit::EditableDocument;
let mut doc = EditableDocument::open("template.docx")?;
let n = doc.replace_text("{{name}}", "Alice");
println!("{n} 处替换");
doc.save("out.docx")?;
replace_text 在 DOCX 中遍历 <w:t> 元素,在 PPTX 中遍历 <a:t> 元素,返回替换次数(XLSX 返回 0 — 改用 set_cell)。
写入 XLSX 单元格
use office_oxide::edit::EditableDocument;
use office_oxide::xlsx::edit::CellValue;
let mut wb = EditableDocument::open("budget.xlsx")?;
wb.set_cell(0, "B2", CellValue::Number(42.0))?;
wb.set_cell(0, "A1", CellValue::String("Total".into()))?;
wb.set_cell(0, "C1", CellValue::Boolean(true))?;
wb.set_cell(0, "D1", CellValue::Empty)?;
wb.save("budget.xlsx")?;
工作表索引从 0 开始;单元格引用使用标准电子表格记号(A1、AA12)。
与格式无关的 IR
DocumentIR 是不同格式之间的结构桥梁 — 它支撑了 to_html、save_as 以及旧版格式转换。它实现 Serialize / Deserialize,可以输出为 JSON。
let legacy = Document::open("old.doc")?;
legacy.save_as("migrated.docx")?; // CFB → OOXML 一行搞定
从字节打开
use std::io::Cursor;
use office_oxide::{Document, DocumentFormat};
let bytes = std::fs::read("file.pptx")?;
let doc = Document::from_reader(Cursor::new(bytes), DocumentFormat::Pptx)?;
内存映射打开
启用 mmap 功能开关后,Document::open_mmap 不会把大 OOXML 文件复制进堆内存:
let doc = Document::open_mmap("huge.xlsx")?;
仅 DOCX/XLSX/PPTX 可 mmap;旧版 CFB 解析器需要所有权缓冲。
错误处理
所有可能失败的入口都返回 office_oxide::Result<T>,即 Result<T, OfficeError>。错误枚举覆盖 IO、解析、不支持的格式以及提取失败。
use office_oxide::{Document, OfficeError};
match Document::open("weird.file") {
Ok(doc) => println!("{}", doc.plain_text()),
Err(OfficeError::UnsupportedFormat(ext)) => eprintln!("无法打开 .{ext}"),
Err(e) => eprintln!("失败: {e}"),
}
故障排查
| 症状 | 原因 |
|---|---|
UnsupportedFormat("(none)") |
路径无扩展名 — 用 from_reader 显式传 DocumentFormat。 |
| DOC 文本乱码 | 文件可能加密或使用罕见 piece-table 编码。检查 CFB 魔术 D0 CF 11 E0。 |
| DOCX 缺少超链接 | 超链接通过 w:rels 解析。确认 ZIP 内 .rels 旁文件存在。 |
| 小栈线程上栈溢出 | office_oxide 在 RLIMIT_STACK < 12 MB 时会启动 16 MB 解析线程。自定义线程池里请用 Builder::stack_size(16 * 1024 * 1024)。 |
相关链接
- Python 快速上手 — 同样的 API
- 性能基准 — 6,062 个文件的完整数据
- 架构: ARCHITECTURE.md
- crate: crates.io、文档: docs.rs