目录

Golang+LibreOffice6.2 实战:Word/Excel/PPTX 转 PDF/HTML

最近遇到一个核心需求:用户上传的 Word(.doc/.docx)、Excel(.xls/.xlsx)、PPTX 文件,需要支持在线预览。

调研后发现,最稳妥的方案是先将这些文档转成 PDF(适合正式预览)或 HTML(适合轻量预览),

而 LibreOffice 作为免费开源的办公套件,不仅支持多格式转换,还能通过命令行调用,完美适配 Golang 的集成需求。

本文基于 LibreOffice 6.2 版本(稳定性强、兼容性好,实测支持 Office 2003-2019 格式),结合 Golang 的exec包封装转换逻辑,

记录分享从环境搭建到代码实现,再到中文乱码、转换超时等坑点解决,希望对大家有所帮助。

一、核心原理

Golang + LibreOffice 转换的实现逻辑:

  1. LibreOffice 转换能力:LibreOffice 内置文档格式解析引擎,支持通过命令行工具 soffice(Linux/Mac)或 soffice.exe(Windows)执行无界面转换,无需打开 GUI 窗口。
  2. Golang 调用方式:Golang 通过 os/exec 包执行系统命令,调用 LibreOffice 的转换指令,捕获执行结果(成功 / 失败)和输出日志,实现程序层面的自动化转换。
  3. 转换流程:用户上传文档 → Golang 接收文件并保存到临时目录 → 调用 LibreOffice 命令行转换 → 读取转换后的 PDF/HTML 文件 → 返回给前端预览。

二、环境准备

安装 LibreOffice6.2 并配置

以下是 Linux(CentOS/Ubuntu)和 Windows 的详细步骤:

(一)linux 系统

以 Centos 7 为例

直接下载

# CentOS 7(64位)示例:下载RPM包
wget https://downloadarchive.documentfoundation.org/libreoffice/old/6.2.0/rpm/x86_64/LibreOffice_6.2.0_Linux_x86-64_rpm.tar.gz

# Ubuntu 18.04(64位)示例:下载DEB包
wget https://downloadarchive.documentfoundation.org/libreoffice/old/6.2.0/deb/x86_64/LibreOffice_6.2.0_Linux_x86-64_deb.tar.gz

⚠️地址可能失效,请以官网最新地址为准:下载 LibreOffice | LibreOffice 简体中文官方网站 - 自由免费的办公套件

解压并安装

# CentOS 7安装步骤
tar -zxvf LibreOffice_6.2.0_Linux_x86-64_rpm.tar.gz
cd LibreOffice_6.2.0.3_Linux_x86-64_rpm/RPMS/
# 安装所有必需组件(含Writer/Calc/Impress,对应Word/Excel/PPTX)
yum localinstall *.rpm -y

# Ubuntu 18.04安装步骤
tar -zxvf LibreOffice_6.2.0_Linux_x86-64_deb.tar.gz
cd LibreOffice_6.2.0.3_Linux_x86-64_deb/DEBS/
dpkg -i *.deb
# 修复依赖缺失
apt -f install -y

安装依赖组件

关键!避免转换失败

LibreOffice 转换需要 Java 运行环境和字体支持,必须安装:

# CentOS 7
yum install java-1.8.0-openjdk fontconfig -y

# Ubuntu 18.04
apt install openjdk-8-jre fontconfig -y

验证安装

# 查看LibreOffice版本(输出6.2.0即成功)
soffice --version

# 测试命令行转换(转换一个测试Word文件到PDF)
soffice --headless --invisible --nodefault --norestore --nofirststartwizard --convert-to pdf --outdir /tmp /path/to/test.docx

(二)windows 系统

  • 下载

    官网下载 Windows 版本:下载 LibreOffice | LibreOffice 简体中文官方网站 - 自由免费的办公套件

  • 安装

    • 安装路径建议默认(C:\Program Files\LibreOffice 6.2\),方便后续调用。
    • 安装时勾选 “Writer”“Calc”“Impress” 组件(默认已勾选,无需修改)。
    • 安装完成后,将 C:\Program Files\LibreOffice 6.2\program 加入系统环境变量 PATH,确保soffice.exe可全局调用。
  • 验证安装

    打开 CMD 命令行,执行:

    soffice --version

    输出 “LibreOffice 6.2.0.3” 即成功。

三、Go 实现转换

核心代码如下:

package main

import (
	"errors"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"
)

// ConvertDoc 文档转换核心函数
// inputPath: 输入文件路径(如./test.docx)
// outputDir: 输出目录(如./output)
// targetType: 目标格式(pdf/html)
// 返回值: 输出文件路径、错误信息
func ConvertDoc(inputPath, outputDir, targetType string) (string, error) {
	// 1. 校验参数
	if inputPath == "" {
		return "", errors.New("输入文件路径不能为空")
	}
	if outputDir == "" {
		outputDir = "./output"
	}
	if targetType != "pdf" && targetType != "html" {
		return "", errors.New("目标格式仅支持pdf和html")
	}

	// 2. 检查输入文件是否存在
	if _, err := os.Stat(inputPath); os.IsNotExist(err) {
		return "", fmt.Errorf("输入文件不存在:%s", inputPath)
	}

	// 3. 创建输出目录(不存在则创建)
	if err := os.MkdirAll(outputDir, 0755); err != nil {
		return "", fmt.Errorf("创建输出目录失败:%v", err)
	}

	// 4. 拼接LibreOffice命令(区分Windows和Linux)
	var cmd *exec.Cmd
	sofficePath := "soffice" // Linux/Mac默认命令
	if runtime.GOOS == "windows" {
		// Windows默认安装路径(可根据实际安装路径修改)
		sofficePath = `C:\Program Files\LibreOffice 6.2\program\soffice.exe`
		// 检查soffice.exe是否存在
		if _, err := os.Stat(sofficePath); os.IsNotExist(err) {
			return "", errors.New("Windows系统未找到soffice.exe,请检查LibreOffice安装路径")
		}
	}

	// 转换参数说明:
	// --headless:无界面模式(必须)
	// --invisible:隐藏窗口(避免弹窗)
	// --nodefault:不加载默认文档
	// --norestore:不恢复之前的文档
	// --nofirststartwizard:不显示首次启动向导
	// --convert-to:指定目标格式(pdf/html)
	// --outdir:指定输出目录
	args := []string{
		"--headless",
		"--invisible",
		"--nodefault",
		"--norestore",
		"--nofirststartwizard",
		fmt.Sprintf("--convert-to=%s", targetType),
		fmt.Sprintf("--outdir=%s", outputDir),
		inputPath,
	}

	cmd = exec.Command(sofficePath, args...)

	// 5. 捕获命令输出(方便调试)
	var output strings.Builder
	cmd.Stdout = &output
	cmd.Stderr = &output

	// 6. 设置命令执行超时(避免长时间卡住,默认30秒)
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	cmd = cmd.WithContext(ctx)

	// 7. 执行命令
	log.Printf("开始转换:输入文件=%s,目标格式=%s", inputPath, targetType)
	if err := cmd.Run(); err != nil {
		return "", fmt.Errorf("转换失败:%v,命令输出:%s", err, output.String())
	}

	// 8. 拼接输出文件路径(默认与输入文件同名,后缀为targetType)
	inputFileName := filepath.Base(inputPath)
	outputFileName := strings.TrimSuffix(inputFileName, filepath.Ext(inputFileName)) + "." + targetType
	outputPath := filepath.Join(outputDir, outputFileName)

	// 9. 检查输出文件是否存在(避免转换成功但文件缺失)
	if _, err := os.Stat(outputPath); os.IsNotExist(err) {
		return "", fmt.Errorf("转换命令执行成功,但未找到输出文件:%s", outputPath)
	}

	log.Printf("转换成功:输出文件=%s", outputPath)
	return outputPath, nil
}

调用测试:

package main

import (
	"context"
	"fmt"
	"log"
)

func main() {
	// 测试参数(根据实际文件路径修改)
	inputDoc := "./test.docx"   // Word文件
	inputExcel := "./test.xlsx" // Excel文件
	inputPPTX := "./test.pptx"  // PPTX文件
	outputDir := "./output"     // 输出目录

	// 1. Word转PDF
	pdfPath, err := ConvertDoc(inputDoc, outputDir, "pdf")
	if err != nil {
		log.Printf("Word转PDF失败:%v", err)
	} else {
		fmt.Printf("Word转PDF成功:%s\n", pdfPath)
	}

	// 2. Excel转HTML
	htmlPath, err := ConvertDoc(inputExcel, outputDir, "html")
	if err != nil {
		log.Printf("Excel转HTML失败:%v", err)
	} else {
		fmt.Printf("Excel转HTML成功:%s\n", htmlPath)
	}

	// 3. PPTX转PDF
	pptxPdfPath, err := ConvertDoc(inputPPTX, outputDir, "pdf")
	if err != nil {
		log.Printf("PPTX转PDF失败:%v", err)
	} else {
		fmt.Printf("PPTX转PDF成功:%s\n", pptxPdfPath)
	}
}

执行可以看到转换成功

常见问题

Q1、中文乱码解决方案

LibreOffice 默认缺少中文字体,转换中文文档时会出现乱码,需手动安装中文字体:

linux 安装字体示例

# 1. 安装Windows常用中文字体(宋体、黑体等)
yum install wqy-microhei-fonts wqy-zenhei-fonts -y

# 2. 刷新字体缓存
fc-cache -fv

# 3. 验证字体是否生效
fc-list | grep "WenQuanYi"

Q2、转换超时?

如果转换大文件(如 100MB + 的 Excel),30 秒超时可能不够,可在ConvertDoc函数中增加超时参数配置:

// 优化后的函数参数:增加timeout参数
func ConvertDoc(inputPath, outputDir, targetType string, timeout time.Duration) (string, error) {
	// ... 其他代码不变 ...
	// 超时默认30秒,支持自定义
	if timeout <= 0 {
		timeout = 30 * time.Second
	}
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	// ...
}

Q3、转换失败:报错 “Headless mode is not supported on Windows”

Windows 系统下 LibreOffice 6.2 的--headless参数兼容性问题,部分环境会提示不支持。

移除--headless参数,仅保留--invisible,修改 args 为

args := []string{
    "--invisible",
    "--nodefault",
    "--norestore",
    "--nofirststartwizard",
    fmt.Sprintf("--convert-to=%s", targetType),
    fmt.Sprintf("--outdir=%s", outputDir),
    inputPath,
}

如果你的场景需要处理更复杂的文档(如带宏的 Office 文件、特殊格式表格),或需要更高的转换速度,欢迎留言讨论,我会分享进一步的优化方案!

版权声明

未经授权,禁止转载本文章。
如需转载请保留原文链接并注明出处。即视为默认获得授权。
未保留原文链接未注明出处或删除链接将视为侵权,必追究法律责任!

本文原文链接: https://fiveyoboy.com/articles/go-libreoffice-convert/

备用原文链接: https://blog.fiveyoboy.com/articles/go-libreoffice-convert/