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 转换的实现逻辑:
- LibreOffice 转换能力:LibreOffice 内置文档格式解析引擎,支持通过命令行工具
soffice(Linux/Mac)或soffice.exe(Windows)执行无界面转换,无需打开 GUI 窗口。 - Golang 调用方式:Golang 通过
os/exec包执行系统命令,调用 LibreOffice 的转换指令,捕获执行结果(成功 / 失败)和输出日志,实现程序层面的自动化转换。 - 转换流程:用户上传文档 → 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/