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