C# / .NET Office 라이브러리 — 빠른 시작
OfficeOxide는 Rust office_oxide 라이브러리의 .NET 바인딩입니다. .NET 애플리케이션에 빠르고 할당이 적은 DOCX / XLSX / PPTX / DOC / XLS / PPT 파싱·변환·편집 기능을 제공합니다 — 내부적으로 AOT 호환 LibraryImport P/Invoke를 사용합니다.
설치
dotnet add package OfficeOxide --version 0.1.0
.NET 8 또는 .NET 10이 필요합니다. NuGet 패키지는 runtimes/<rid>/native/ 아래에 win-x64, linux-x64, linux-arm64, osx-x64, osx-arm64용 사전 빌드 네이티브 라이브러리를 포함합니다. dotnet publish가 자동으로 적절한 것을 바이너리 옆에 놓습니다.
문서 읽기
using OfficeOxide;
using var doc = Document.Open("report.docx");
Console.WriteLine(doc.PlainText());
핵심 API
Document는 읽기 전용 핸들입니다. using으로 dispose하여 네이티브 메모리를 해제하세요.
using OfficeOxide;
using var doc = Document.Open("file.xlsx");
Console.WriteLine(doc.Format); // "xlsx"
Console.WriteLine(doc.PlainText());
Console.WriteLine(doc.ToMarkdown());
Console.WriteLine(doc.ToHtml());
Console.WriteLine(doc.ToIrJson());
doc.SaveAs("file.docx"); // 대상 형식은 확장자에서 추론
블로킹 I/O를 위한 비동기 래퍼:
using var doc = await Document.OpenAsync("huge.pptx", ct);
바이트에서 열기(임시 파일 불필요):
byte[] data = File.ReadAllBytes("report.docx");
using var doc = Document.FromBytes(data, "docx");
format은 "docx", "xlsx", "pptx", "doc", "xls", "ppt" 중 하나여야 합니다.
원샷 호출용 정적 헬퍼:
string text = OfficeOxide.ExtractText("file.docx");
string md = OfficeOxide.ToMarkdown("file.pptx");
string html = OfficeOxide.ToHtml("file.xlsx");
string? fmt = Document.DetectFormat("mystery.bin"); // 미지원 시 null
Console.WriteLine(Document.Version); // "0.1.0"
편집
편집은 변경되지 않은 모든 OPC 파트(이미지, 차트, 관계)를 보존합니다. DOCX, XLSX, PPTX만 지원합니다.
using OfficeOxide;
using var ed = EditableDocument.Open("template.docx");
long n = ed.ReplaceText("{{name}}", "Alice");
Console.WriteLine($"{n}건 치환");
ed.Save("out.docx");
ReplaceText는 치환 횟수를 반환합니다(XLSX에서는 0 — SetCell을 사용).
DOCX / PPTX의 텍스트 치환
using var ed = EditableDocument.Open("slides.pptx");
ed.ReplaceText("Q3", "Q4");
ed.ReplaceText("2024", "2025");
byte[] bytes = ed.SaveToBytes();
File.WriteAllBytes("slides_q4.pptx", bytes);
XLSX 셀 설정(네 가지 오버로드)
using var wb = EditableDocument.Open("budget.xlsx");
wb.SetCell(0u, "A1", "Total"); // 문자열 오버로드
wb.SetCell(0u, "B1", 42.5); // double 오버로드
wb.SetCell(0u, "C1", true); // bool 오버로드
wb.SetCellEmpty(0u, "D1"); // 셀 비움
wb.Save("budget.xlsx");
sheetIndex는 0부터; cellRef는 표준 스프레드시트 표기법(A1, AA12).
형식 무관 IR
ToIrJson()은 Rust DocumentIR 형태와 일치하는 JSON 문자열을 반환합니다:
using System.Text.Json;
using var doc = Document.Open("report.docx");
string json = doc.ToIrJson();
using var ir = JsonDocument.Parse(json);
foreach (var section in ir.RootElement.GetProperty("sections").EnumerateArray())
{
if (section.TryGetProperty("title", out var t) && t.ValueKind != JsonValueKind.Null)
Console.WriteLine(t.GetString());
}
바이트 기반 파이프라인
using var http = new HttpClient();
byte[] data = await http.GetByteArrayAsync("https://example.com/file.docx");
using var doc = Document.FromBytes(data, "docx");
Console.WriteLine(doc.ToMarkdown());
레거시 형식
using var legacy = Document.Open("old.xls");
legacy.SaveAs("modern.xlsx");
AOT / 트리밍
프로젝트는 IsAotCompatible=true와 IsTrimmable=true를 설정합니다. 모든 P/Invoke가 LibraryImport 소스 생성기를 사용하므로 dotnet publish -c Release -p:PublishAot=true로 단일 self-contained 실행 파일을 얻을 수 있습니다.
오류
실패는 타입화된 Code 속성을 가진 OfficeOxideException을 발생시킵니다:
try
{
using var doc = Document.Open("missing.docx");
}
catch (OfficeOxideException ex)
{
Console.WriteLine($"code={ex.Code} op={ex.Operation}");
}
dispose된 핸들에서 메서드를 호출하면 ObjectDisposedException이 발생합니다.
| Code | 이름 | 의미 |
|---|---|---|
| 0 | Ok |
성공 |
| 1 | InvalidArg |
null / 빈 값 / 잘못된 format 문자열 |
| 2 | Io |
파일 시스템 오류 |
| 3 | Parse |
문서가 잘못됨 |
| 4 | Extraction |
파싱은 성공했지만 렌더링 실패 |
| 5 | Internal |
버그 — 이슈를 등록해 주세요 |
| 6 | Unsupported |
확장자/기능 미지원 |
문제 해결
| 증상 | 해결 |
|---|---|
DllNotFoundException: office_oxide |
네이티브 라이브러리가 바이너리 옆에 복사되지 않았습니다. 단순한 dotnet build 대신 dotnet publish를 실행하세요. |
Windows에서 BadImageFormatException |
CPU 아키 불일치 — 맞는 win-x64 또는 win-arm64 빌드를 배포하세요. |
.doc에서 OfficeOxideException 코드 Unsupported |
확장자가 소문자인지 확인하거나 FromBytes로 형식을 명시하세요. |
| 트리밍 후 심볼 누락 | <TrimmerRootAssembly>에 OfficeOxide를 추가하세요. |
| macOS “개발자를 확인할 수 없음” | xattr -d com.apple.quarantine /path/to/liboffice_oxide.dylib을 실행하거나 번들에 서명하세요. |