Skip to content

Node.js Office 库 — 快速上手

office-oxide npm 包是 原生 Node.js 绑定:通过 koffi 动态加载 liboffice_oxide,并暴露简洁、地道的 JavaScript API。比 WebAssembly 构建更快、更小,但需要按平台分发预编译产物,而不是单一可移植二进制。

如果需要一个能跨浏览器、打包工具或 Node 运行的单一构件(且不需要原生库),请改用 office-oxide-wasm

安装

npm install office-oxide

postinstall 时会在 node_modules/office-oxide/prebuilds/<platform>-<arch>/ 下查找匹配的预编译原生库。如果找不到,请在首次使用前配置以下任一项:

  1. OFFICE_OXIDE_LIB — 库的绝对路径(例如 /opt/office_oxide/liboffice_oxide.so)。
  2. 预编译目录 — 把库放到包内的 prebuilds/<platform>-<arch>/(如 linux-x64darwin-arm64win32-x64)。
  3. 系统库路径 — 安装到 LD_LIBRARY_PATH / DYLD_LIBRARY_PATH / PATH 能找到的位置。

支持 Node 18+。

读取文档

import { Document } from 'office-oxide';

const doc = Document.open('report.docx');
try {
  console.log(doc.plainText());
} finally {
  doc.close();
}

或使用 TC39 显式资源管理(Node 22+):

import { Document } from 'office-oxide';

using doc = Document.open('report.docx');
console.log(doc.plainText());
// 离开作用域时会自动调用 doc.close()

一次性辅助函数:

import { extractText } from 'office-oxide';
console.log(extractText('report.docx'));

核心 API

import { Document } from 'office-oxide';

const doc = Document.open('file.xlsx');
try {
  console.log(doc.format);         // "xlsx"
  console.log(doc.plainText());
  console.log(doc.toMarkdown());
  console.log(doc.toHtml());
  const ir = doc.toIr();           // 解析后的对象

  doc.saveAs('file.docx');         // 目标根据扩展名推断
} finally {
  doc.close();
}

从原始字节(Uint8ArrayBuffer)打开:

import { readFileSync } from 'node:fs';
import { Document } from 'office-oxide';

const data = readFileSync('report.pptx');
using doc = Document.fromBytes(data, 'pptx');
console.log(doc.toMarkdown());

format 必须是 'docx' | 'xlsx' | 'pptx' | 'doc' | 'xls' | 'ppt'

模块级辅助函数:

import { extractText, toMarkdown, toHtml, detectFormat, version } from 'office-oxide';

extractText('file.docx');      // string
toMarkdown('file.pptx');       // string
toHtml('file.xlsx');           // string
detectFormat('mystery.bin');   // "docx" | ... | null
version();                     // "0.1.0"

编辑

可编辑句柄在保存时保留所有未修改的 OPC 部件。仅支持 DOCX、XLSX、PPTX。

import { EditableDocument } from 'office-oxide';

using ed = EditableDocument.open('template.docx');
const n = ed.replaceText('{{name}}', 'Alice');
console.log(`${n} 处替换`);
ed.save('out.docx');

写入 XLSX 单元格

import { EditableDocument } from 'office-oxide';

using wb = EditableDocument.open('budget.xlsx');

wb.setCell(0, 'A1', 'Total');   // 字符串
wb.setCell(0, 'B1', 42.5);      // 数字
wb.setCell(0, 'C1', true);      // 布尔
wb.setCell(0, 'D1', null);      // 清空

wb.save('budget.xlsx');

sheetIndex 从 0 开始;cellRef 使用标准电子表格记号。

与格式无关的 IR

using doc = Document.open('report.docx');
const ir = doc.toIr();

for (const section of ir.sections) {
  console.log(section.title);
  for (const el of section.elements) {
    // el.kind: "Heading" | "Paragraph" | "Table" | "List" | ...
  }
}

字节流管道

import { Document } from 'office-oxide';

const res = await fetch('https://example.com/report.docx');
const data = new Uint8Array(await res.arrayBuffer());
using doc = Document.fromBytes(data, 'docx');
console.log(doc.toMarkdown());

旧版格式

using doc = Document.open('old.xls');
doc.saveAs('modern.xlsx');

CommonJS

const { Document } = require('office-oxide');
const doc = Document.open('file.docx');
try { console.log(doc.plainText()); } finally { doc.close(); }

错误

失败会抛出带数字 codeoperation 字段的 OfficeOxideError:

import { Document, OfficeOxideError } from 'office-oxide';

try {
  using doc = Document.open('missing.docx');
} catch (e) {
  if (e instanceof OfficeOxideError) {
    console.error(`code=${e.code} op=${e.operation}`);
  } else {
    throw e;
  }
}
Code 含义
0 OK
1 参数无效
2 IO 错误
3 解析错误
4 提取失败
5 内部错误
6 不支持的格式

故障排查

症状 解决
office-oxide: failed to load native library OFFICE_OXIDE_LIB 设为绝对路径,或把匹配的预编译库放进包内。
koffi: ABI mismatch 平台/架构与 Node 进程不匹配 — 重新安装或获取新的预编译。
TypeError: data must be a Uint8Array or Buffer Document.fromBytes 只接受二进制类型。用 Buffer.from(base64, 'base64')
Document is closed close() 之后或离开 using 作用域之后调用了方法。开新句柄。
旧版 .doc 能打开但显示乱码 加密的 Word 97 文档不会被解密 — 请先用 LibreOffice 解密。

相关链接