Rust-библиотека для Office — быстрый старт
office_oxide — это чисто-Rust крейт для разбора, конвертации и редактирования документов Office: DOCX, XLSX, PPTX плюс их legacy-предшественники DOC, XLS и PPT. Один крейт, единый Document-handle, никаких нативных зависимостей.
Установка
[dependencies]
office_oxide = "0.1.0"
Опциональные фичи:
office_oxide = { version = "0.1.0", features = ["mmap"] } # mmap-открытие больших OOXML
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-handle ведёт себя одинаково для всех форматов — определение по расширению плюс проверка magic-байтами.
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")?; // legacy → 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 выполняет read-modify-write, сохраняя дословно все нетронутые 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 обходит элементы <w:t> в DOCX и <a:t> в PPTX, возвращает количество замен (для 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")?;
Индексы листов нумеруются с нуля; адреса ячеек — стандартная нотация (A1, AA12).
Формат-независимый IR
DocumentIR — структурный мост между форматами. На нём держатся to_html, save_as и legacy-конверсия. Реализует 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)?;
Memory-mapped открытие
С фичей mmap функция Document::open_mmap не копирует крупные OOXML-файлы в кучу:
let doc = Document::open_mmap("huge.xlsx")?;
mmap доступен только для DOCX/XLSX/PPTX; legacy-парсеры CFB требуют owned-буферов.
Ошибки
Все ошибки возвращаются через 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. Проверьте magic CFB D0 CF 11 E0. |
| Отсутствуют гиперссылки в DOCX | Ссылки разрешаются через w:rels. Убедитесь, что .rels-сосед лежит в ZIP. |
| Stack overflow на маленьких стеках потоков | office_oxide поднимает 16 МБ парс-поток, если RLIMIT_STACK < 12 МБ. В своих пулах задайте Builder::stack_size(16 * 1024 * 1024). |
Смотрите также
- Быстрый старт Python — тот же API в Python
- Бенчмарки производительности — полные числа по 6 062 файлам
- Архитектура: ARCHITECTURE.md
- Крейт на crates.io, документация на docs.rs