Skip to content

Go Office 库 — 快速上手

Go 包 github.com/yfedoseev/office_oxide/go 通过 cgo 封装了 office_oxide 的 C FFI,并提供了用于读取、转换和编辑 DOCX / XLSX / PPTX / DOC / XLS / PPT 的地道 Go 类型。

安装

go get github.com/yfedoseev/office_oxide/go@latest

这个绑定在链接时需要 office_oxide C 库,两种提供方式。

方式 1 — 一键安装器(推荐):

go run github.com/yfedoseev/office_oxide/go/cmd/install@latest

安装器会下载与你的 OS/架构匹配的预编译 liboffice_oxide(含头文件),并放到 cgo 能找到的位置。升级后想取得新的 ABI,请重新运行。

方式 2 — 自己设置 cgo flags(你已经从 Rust 源码 cargo build --release --lib 构建好,或库已在系统 prefix 中):

export CGO_CFLAGS="-I/usr/local/include"
export CGO_LDFLAGS="-L/usr/local/lib -loffice_oxide"

读取文档

package main

import (
    "fmt"
    "log"

    officeoxide "github.com/yfedoseev/office_oxide/go"
)

func main() {
    doc, err := officeoxide.Open("report.docx")
    if err != nil {
        log.Fatal(err)
    }
    defer doc.Close()

    text, err := doc.PlainText()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(text)
}

一次性辅助函数:

text, err := officeoxide.ExtractText("report.docx")

核心 API

doc, err := officeoxide.Open("file.xlsx")
if err != nil { log.Fatal(err) }
defer doc.Close()

format, _ := doc.Format()      // "xlsx"
text, _   := doc.PlainText()
md, _     := doc.ToMarkdown()
html, _   := doc.ToHTML()
irJSON, _ := doc.ToIRJSON()

err = doc.SaveAs("file.docx")

Document 包装了一个 C 句柄;如果忘记 Close,finalizer 会释放,但务必优先用 defer doc.Close() 来做确定性清理。

从字节打开(适合流式/无服务器):

data, _ := os.ReadFile("report.pptx")
doc, err := officeoxide.OpenFromBytes(data, "pptx")

format 必须是 "docx""xlsx""pptx""doc""xls""ppt" 之一。

编辑

可编辑句柄在保存时保留所有未修改的 OPC 部件(图片、图表、自定义 XML)。仅支持 DOCX、XLSX、PPTX。

ed, err := officeoxide.OpenEditable("template.docx")
if err != nil { log.Fatal(err) }
defer ed.Close()

n, _ := ed.ReplaceText("{{name}}", "Alice")
fmt.Printf("%d 处替换\n", n)

err = ed.Save("out.docx")

在 DOCX / PPTX 中替换文本

ed, _ := officeoxide.OpenEditable("slides.pptx")
defer ed.Close()

ed.ReplaceText("Q3", "Q4")
ed.ReplaceText("2024", "2025")

buf, _ := ed.SaveToBytes()   // []byte 可直接上传/流式
_ = os.WriteFile("slides_q4.pptx", buf, 0o644)

设置 XLSX 单元格

ed, _ := officeoxide.OpenEditable("budget.xlsx")
defer ed.Close()

ed.SetCell(0, "A1", officeoxide.NewStringCell("Total"))
ed.SetCell(0, "B1", officeoxide.NewNumberCell(42.5))
ed.SetCell(0, "C1", officeoxide.NewBoolCell(true))
ed.SetCell(0, "D1", officeoxide.NewEmptyCell())

ed.Save("budget.xlsx")

请使用 NewStringCellNewNumberCellNewBoolCellNewEmptyCell — 构造函数会为 FFI 调用挑选正确的变体。

与格式无关的 IR

doc.ToIRJSON() 返回与 Rust DocumentIR 模式一致的 JSON。按需 Unmarshal:

import "encoding/json"

irJSON, _ := doc.ToIRJSON()

var ir struct {
    Sections []struct {
        Title    *string           `json:"title"`
        Elements []json.RawMessage `json:"elements"`
    } `json:"sections"`
}
_ = json.Unmarshal([]byte(irJSON), &ir)
fmt.Printf("%d 个 section\n", len(ir.Sections))

不打开就检测格式

fmt := officeoxide.DetectFormat("mystery.bin")  // 不支持时返回 ""

旧版格式

打开方式与 OOXML 相同;SaveAs 会通过 IR 透明转换:

doc, _ := officeoxide.Open("old.xls")
defer doc.Close()
_ = doc.SaveAs("modern.xlsx")

错误

每个可能失败的调用都会返回带类型化 code 和原始 operation 的 *officeoxide.Error:

if _, err := officeoxide.Open("missing.docx"); err != nil {
    var e *officeoxide.Error
    if errors.As(err, &e) {
        fmt.Printf("code=%d op=%s\n", e.Code, e.Op)
    }
}

使用已关闭的句柄会返回 officeoxide.ErrClosed

Code 名称 含义
0 OK 成功
1 INVALID_ARG nil / 空 / 错误的 format 字符串
2 IO 文件系统错误
3 PARSE 文档损坏
4 EXTRACTION 解析成功但渲染失败
5 INTERNAL bug — 请提 issue
6 UNSUPPORTED 扩展名/特性不支持

故障排查

症状 解决
could not determine kind of name for C.office_document_open cgo 看不到 C 头。运行安装器或设置 CGO_CFLAGS
链接时 cannot find -loffice_oxide 设置 CGO_LDFLAGS="-L/path/to/lib -loffice_oxide" 或运行安装器。
运行时 cannot open shared object file 把库目录加入 LD_LIBRARY_PATH(Linux)、DYLD_LIBRARY_PATH(macOS),或把 DLL 放到二进制旁边(Windows)。
.doc/.xlsunsupported format 确保扩展名小写,或调用 OpenFromBytes(data, "doc")
交叉编译失败 cgo 需要匹配目标的 C 工具链。用 zig ccCC=aarch64-linux-gnu-gcc

相关链接