Skip to content

C / FFI Office 库 — 快速上手

office_oxide 的 C API 是 Rust 内核之上一层稳定且轻薄的 ABI。所有上层绑定(Go、C#、Node.js 原生)都调用同一组入口点。如果某个生态没有现成的封装,你随时可以直接链接 C 库。

权威接口在 include/office_oxide_c/office_oxide.h。本指南介绍同一 API。

安装

方式 1 — 从 Rust 源码构建

git clone https://github.com/yfedoseev/office_oxide
cd office_oxide
cargo build --release --lib

共享库会输出到 target/release/:

OS 文件
Linux liboffice_oxide.so
macOS liboffice_oxide.dylib
Windows office_oxide.dll(+ .lib 导入库)

头文件位于 include/office_oxide_c/office_oxide.h

方式 2 — 安装预编译库

install -Dm644 include/office_oxide_c/office_oxide.h /usr/local/include/office_oxide.h
install -Dm755 target/release/liboffice_oxide.so     /usr/local/lib/liboffice_oxide.so

读取文档

#include <stdio.h>
#include <stdlib.h>
#include "office_oxide.h"

int main(void) {
    int err = 0;
    char *text = office_extract_text("report.docx", &err);
    if (!text) {
        fprintf(stderr, "office_oxide failed: code=%d\n", err);
        return 1;
    }
    printf("%s\n", text);
    office_oxide_free_string(text);
    return 0;
}

构建并运行:

cc quickstart.c -I/usr/local/include -L/usr/local/lib -loffice_oxide -o quickstart
LD_LIBRARY_PATH=/usr/local/lib ./quickstart

核心 API

库信息

const char *version = office_oxide_version();          // "0.1.0" — 不要 free
const char *fmt     = office_oxide_detect_format("f"); // "docx"/... 或 NULL

Document(只读)

int err = 0;
OfficeDocumentHandle *doc = office_document_open("file.xlsx", &err);
if (!doc) { /* 处理 err */ }

const char *fmt = office_document_format(doc);         // "xlsx" — 不要 free

char *text = office_document_plain_text(doc, &err);
char *md   = office_document_to_markdown(doc, &err);
char *html = office_document_to_html(doc, &err);
char *ir   = office_document_to_ir_json(doc, &err);

if (office_document_save_as(doc, "file.docx", &err) != 0) { /* 处理 err */ }

office_oxide_free_string(text);
office_oxide_free_string(md);
office_oxide_free_string(html);
office_oxide_free_string(ir);

office_document_free(doc);

从内存缓冲打开:

uint8_t *data = ...;
size_t   len  = ...;
OfficeDocumentHandle *doc =
    office_document_open_from_bytes(data, len, "docx", &err);

format 必须是 "docx" | "xlsx" | "pptx" | "doc" | "xls" | "ppt" 中的一个。

EditableDocument

编辑会保留所有未修改的 OPC 部件。仅支持 DOCX、XLSX、PPTX。

int err = 0;
OfficeEditableHandle *ed = office_editable_open("template.docx", &err);
if (!ed) { /* 处理 err */ }

int64_t n = office_editable_replace_text(ed, "{{name}}", "Alice", &err);
if (n < 0) { /* 处理 err */ }
printf("%lld 处替换\n", (long long)n);

if (office_editable_save(ed, "out.docx", &err) != 0) { /* 处理 err */ }

office_editable_free(ed);

设置 XLSX 单元格:

OfficeEditableHandle *wb = office_editable_open("budget.xlsx", &err);

office_editable_set_cell(wb, 0, "A1", OFFICE_CELL_STRING, "Total", 0.0,  &err);
office_editable_set_cell(wb, 0, "B1", OFFICE_CELL_NUMBER,  NULL,   42.5, &err);
office_editable_set_cell(wb, 0, "C1", OFFICE_CELL_BOOLEAN, NULL,   1.0,  &err);
office_editable_set_cell(wb, 0, "D1", OFFICE_CELL_EMPTY,   NULL,   0.0,  &err);

office_editable_save(wb, "budget.xlsx", &err);
office_editable_free(wb);

布尔值: value_num 非零即为 true。

序列化到堆缓冲:

size_t   out_len = 0;
uint8_t *buf     = office_editable_save_to_bytes(ed, &out_len, &err);
if (!buf) { /* 处理 err */ }
/* 上传或流式 buf[0..out_len] */
office_oxide_free_bytes(buf, out_len);

一次性辅助

char *text = office_extract_text("file.docx", &err);
char *md   = office_to_markdown("file.pptx", &err);
char *html = office_to_html("file.xlsx", &err);
/* 每个都用 office_oxide_free_string 释放 */

内存规则

  • office_document_*office_editable_* 以及一次性辅助函数返回的 char* 必须用 office_oxide_free_string(ptr) 释放。
  • 配合 out_len 输出参数返回的 uint8_t* 必须用 office_oxide_free_bytes(ptr, len) 释放,len 与 API 写入 out_len 的值一致。
  • 不透明句柄要用对应的 *_free() 释放。
  • office_oxide_versionoffice_oxide_detect_formatoffice_document_format 返回的 const char* 是静态的 — 不要 free

错误

每个可能失败的调用都接收 int *error_code 出参:

int err = 0;
OfficeDocumentHandle *doc = office_document_open("missing.docx", &err);
if (!doc) {
    switch (err) {
        case OFFICE_ERR_IO:    fputs("io 错误\n", stderr); break;
        case OFFICE_ERR_PARSE: fputs("解析错误\n", stderr); break;
        /* ... */
    }
}
含义
OFFICE_OK 0 成功
OFFICE_ERR_INVALID_ARG 1 nil 指针 / 未知 format 字符串
OFFICE_ERR_IO 2 文件系统错误
OFFICE_ERR_PARSE 3 文档损坏
OFFICE_ERR_EXTRACTION 4 解析成功但渲染失败
OFFICE_ERR_INTERNAL 5 bug — 请提 issue
OFFICE_ERR_UNSUPPORTED 6 扩展名/特性不支持

单元格值常量

OFFICE_CELL_EMPTY 0
OFFICE_CELL_STRING 1
OFFICE_CELL_NUMBER 2
OFFICE_CELL_BOOLEAN 3

旧版格式

office_document_open 打开 — 通过扩展名识别,魔术字节验证。office_document_save_as 透明地完成旧版格式 → OOXML 转换:

OfficeDocumentHandle *doc = office_document_open("old.xls", &err);
office_document_save_as(doc, "modern.xlsx", &err);
office_document_free(doc);

线程安全

每个句柄属于调用者 — 不要在线程间共享同一句柄。不同句柄可以并行使用,库本身是可重入的。

C++

头文件用 extern "C" 守卫包装,可直接放进 C++ 翻译单元:

#include "office_oxide.h"

配合 RAII 包装(如 std::unique_ptr<OfficeDocumentHandle, decltype(&office_document_free)>)让清理具备异常安全性。

故障排查

症状 解决
链接器: undefined reference to office_document_open 加上 -loffice_oxide 和对应 -L;确认库以 --release --lib 构建。
运行时: error while loading shared libraries: liboffice_oxide.so 把库目录加入 LD_LIBRARY_PATH(Linux)、DYLD_LIBRARY_PATH(macOS),或放到 exe 旁(Windows)。
open_from_bytesOFFICE_ERR_INVALID_ARG format 必须严格是 `“docx”
双重释放或堆损坏 检查每个 char*office_oxide_free_string 释放,每个字节缓冲用 office_oxide_free_bytes(ptr, len)(用原始 out_len)。
office_editable_replace_text 在 XLSX 上返回 0 这是预期 — 表格编辑请用 office_editable_set_cell

相关链接