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")
请使用 NewStringCell、NewNumberCell、NewBoolCell 或 NewEmptyCell — 构造函数会为 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/.xls 的 unsupported format |
确保扩展名小写,或调用 OpenFromBytes(data, "doc")。 |
| 交叉编译失败 | cgo 需要匹配目标的 C 工具链。用 zig cc 或 CC=aarch64-linux-gnu-gcc。 |
相关链接
- 性能基准
- 包: pkg.go.dev
- C 头文件 —
include/office_oxide_c/office_oxide.h