Skip to content

Go-библиотека для Office — быстрый старт

Пакет Go github.com/yfedoseev/office_oxide/go оборачивает C FFI office_oxide через cgo и даёт идиоматичные Go-типы для чтения, конвертации и редактирования DOCX / XLSX / PPTX / DOC / XLS / PPT.

Установка

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

Привязке нужна C-библиотека office_oxide на этапе линковки. Два способа её получить.

Вариант 1 — установщик одной строкой (рекомендуется):

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

Установщик скачивает подходящий prebuilt-liboffice_oxide (и заголовок) под вашу ОС/архитектуру и кладёт туда, где cgo сможет их найти. После апгрейда запустите снова, чтобы подхватить новый ABI.

Вариант 2 — задать cgo-флаги вручную, если вы собрали библиотеку из исходников 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-handle; финализатор освободит его, если забудете Close, но всегда предпочитайте defer doc.Close() для детерминированного освобождения.

Открытие из байтов (полезно для стриминга/serverless):

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

format должен быть "docx", "xlsx", "pptx", "doc", "xls", "ppt".

Редактирование

Editable-handle сохраняет все нетронутые 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() возвращает JSON, совпадающий со схемой Rust DocumentIR. Анмаршалите в нужный вам тип:

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 секций\n", len(ir.Sections))

Определение формата без открытия

fmt := officeoxide.DetectFormat("mystery.bin")  // "" если не поддерживается

Legacy-форматы

Открываются как OOXML; SaveAs прозрачно конвертирует через IR:

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

Ошибки

Любой вызов с возможной ошибкой возвращает *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)
    }
}

Использование закрытой handle возвращает officeoxide.ErrClosed.

Код Имя Значение
0 OK успех
1 INVALID_ARG nil / пусто / неправильная строка формата
2 IO ошибка файловой системы
3 PARSE повреждённый документ
4 EXTRACTION парсинг ок, но рендер сорвался
5 INTERNAL баг — заведите issue
6 UNSUPPORTED расширение/фича не поддерживаются

Диагностика

Симптом Что делать
could not determine kind of name for C.office_document_open cgo не видит заголовки. Запустите установщик или задайте 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).
unsupported format для .doc/.xls Убедитесь, что расширение в нижнем регистре, или вызовите OpenFromBytes(data, "doc").
Кросс-компиляция падает cgo нужен C-toolchain под целевую платформу. Используйте zig cc или CC=aarch64-linux-gnu-gcc.

Смотрите также