Biblioteca Office para Rust — Inicio Rápido
office_oxide es una crate en Rust puro para analizar, convertir y editar documentos de Office: DOCX, XLSX, PPTX, junto con sus predecesores binarios DOC, XLS y PPT. Una sola crate, un handle Document unificado, cero dependencias nativas.
Instalación
[dependencies]
office_oxide = "0.1.0"
Features opcionales:
office_oxide = { version = "0.1.0", features = ["mmap"] } # apertura mmap para OOXML grandes
office_oxide = { version = "0.1.0", features = ["parallel"] } # ayudantes de parseo paralelo basados en rayon
Leer un documento
use office_oxide::Document;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let doc = Document::open("report.docx")?;
println!("{}", doc.plain_text());
Ok(())
}
O el helper de una sola llamada:
let text = office_oxide::extract_text("report.docx")?;
API principal
El handle Document se comporta igual en todos los formatos — detección por extensión más verificación con magic bytes.
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 independiente del formato
doc.save_as("file.docx")?; // heredado → OOXML también funciona
Document::open acepta AsRef<Path>; Document::from_reader toma Read + Seek + Send + 'static con un DocumentFormat explícito.
Atajos a nivel de módulo:
let text = office_oxide::extract_text("file.docx")?;
let md = office_oxide::to_markdown("file.pptx")?;
let html = office_oxide::to_html("file.xlsx")?;
Acceso específico al formato
Cuando necesites datos propios del formato — hojas, diapositivas, celdas de tabla — desempaqueta el documento interno:
if let Some(xlsx) = doc.as_xlsx() {
for sheet in xlsx.sheets() {
println!("sheet: {}", sheet.name());
}
}
El mismo patrón aplica a as_docx, as_pptx, as_doc, as_xls y as_ppt.
Edición
EditableDocument ejecuta read-modify-write y conserva todas las partes OPC sin tocar (imágenes, gráficos, estilos, relaciones). Solo DOCX, XLSX y PPTX.
use office_oxide::edit::EditableDocument;
let mut doc = EditableDocument::open("template.docx")?;
let n = doc.replace_text("{{name}}", "Alice");
println!("{n} reemplazos");
doc.save("out.docx")?;
replace_text recorre <w:t> en DOCX y <a:t> en PPTX, devolviendo el número de reemplazos (XLSX devuelve 0 — usa set_cell).
Establecer celdas 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")?;
Los índices de hoja empiezan en cero; las referencias de celda usan la notación estándar (A1, AA12).
IR independiente del formato
DocumentIR es el puente estructural entre formatos — soporta to_html, save_as y la conversión de formatos heredados. Implementa Serialize / Deserialize, así que puede emitir JSON para herramientas posteriores.
let legacy = Document::open("old.doc")?;
legacy.save_as("migrated.docx")?; // CFB → OOXML en una línea
Abrir desde bytes
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)?;
Apertura mediante memory map
Con la feature mmap, Document::open_mmap evita copiar archivos OOXML grandes al heap:
let doc = Document::open_mmap("huge.xlsx")?;
Solo DOCX/XLSX/PPTX admiten mmap; los parsers CFB heredados requieren búferes propios.
Errores
Cada punto de entrada con posibles fallos devuelve office_oxide::Result<T>, es decir, Result<T, OfficeError>. El enum cubre IO, parseo, formato no soportado y fallos de extracción.
use office_oxide::{Document, OfficeError};
match Document::open("weird.file") {
Ok(doc) => println!("{}", doc.plain_text()),
Err(OfficeError::UnsupportedFormat(ext)) => eprintln!("no se puede abrir .{ext}"),
Err(e) => eprintln!("falló: {e}"),
}
Solución de problemas
| Síntoma | Causa probable |
|---|---|
UnsupportedFormat("(none)") |
Ruta sin extensión — abre con from_reader y DocumentFormat explícito. |
| Texto DOC ilegible | El archivo puede estar cifrado o usar una piece-table inusual. Verifica el magic CFB D0 CF 11 E0. |
| Hyperlinks ausentes en DOCX | Los hyperlinks se resuelven vía w:rels. Comprueba que el .rels esté dentro del ZIP. |
| Stack overflow en hilos de pila pequeña | office_oxide lanza un hilo de parseo de 16 MB cuando RLIMIT_STACK < 12 MB. En pools propios usa Builder::stack_size(16 * 1024 * 1024). |
Véase también
- Inicio rápido en Python — la misma API en Python
- Benchmarks de rendimiento — cifras completas sobre 6.062 archivos
- Arquitectura: ARCHITECTURE.md
- Crate en crates.io, docs en docs.rs