Skip to content

Rust Office 라이브러리 — 빠른 시작

office_oxide는 Office 문서(DOCX, XLSX, PPTX 및 레거시 바이너리 형식 DOC, XLS, PPT)를 파싱·변환·편집하는 순수 Rust 크레이트입니다. 단일 크레이트, 통합된 Document 핸들, 네이티브 의존성 0.

설치

[dependencies]
office_oxide = "0.1.0"

선택적 피처:

office_oxide = { version = "0.1.0", features = ["mmap"] }       # 큰 OOXML을 위한 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::openAsRef<Path>를, Document::from_reader는 명시적인 DocumentFormat과 함께 Read + Seek + Send + 'static을 받습니다.

모듈 레벨 단축:

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")?;

mmap 가능한 것은 DOCX/XLSX/PPTX뿐 — 레거시 CFB 파서는 소유 버퍼가 필요합니다.

오류

모든 실패 가능 진입점은 office_oxide::Result<T>(즉 Result<T, OfficeError>)를 반환합니다. enum은 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 사이드카가 존재하는지 확인하세요.
작은 스택 스레드에서 stack overflow office_oxideRLIMIT_STACK < 12 MB일 때 16 MB 파싱 스레드를 만듭니다. 자체 스레드 풀에서는 Builder::stack_size(16 * 1024 * 1024)를 지정하세요.

더 보기