本文介绍在 windows 平台使用 go 语言调用系统打印 api,将 utf-8 编码的纯文本(固定宽度字体)发送至默认打印机的完整实现方案,基于 `github.com/alexbrainman/printer` 封装库,无需外部依赖或渲染引擎。
在 Go 生态中,原生打印支持并非标准库功能,尤其面向 Windows 的底层 GDI 打印流程需绕过高级抽象(如 PDF 渲染或 Web 预览),直接对接 Windows 打印子系统。对于消息服务器等后台服务场景,要求轻量、可靠、无 GUI 交互——此时推荐使用 github.com/alexbrainman/printer 这一专为 Windows 设计的 Go 绑定库。它封装了 CreateDC, StartDoc, StartPage, WritePrinter, EndPage, EndDoc 等核心 Win32 GDI 打印 API,屏蔽了复杂句柄管理和字符编码转换细节。
以下是一个生产就绪的打印示例(已适配 UTF-8 文本与等宽字体需求):
package main
import (
"fmt"
"log"
prt "github.com/alexbrainman/printer"
)
func printToDefault(text string) error {
// 获取系统默认打印机名称
printerName, err := prt.Default()
if err != nil {
return fmt.Errorf("failed to get default printer: %w", err)
}
// 打开打印机句柄
p, err := prt.Open(printerName)
if err != nil {
return fmt.Errorf("failed to open printer %q: %w", printerName, err)
}
defer p.Close() // 确保资源释放
// 启动文档(文档名建议含时间戳或 ID,便于追踪)
docName := fmt.Sprintf("GoPrint-%d", time.Now().UnixNano())
if err = p.StartDocument(docName, "TEXT"); err != nil {
return fmt.Errorf("failed to start document: %w", err)
}
defer p.DocumentEnd() // 使用 defer 确保异常时也能结束文档
// 开始新页面
if err = p.StartPage(); err != nil {
return fmt.Errorf("failed to start page: %w", err)
}
defer p.PageEnd() // 同样确保页结束
// 写入 UTF-8 文本(Windows GDI 默认按 OEM 字符集解释字节流)
// ⚠️ 关键:为正确显示中文等 UTF-8 字符,需先转换为系统活动代码页(如 GBK/CP936)
// 以下使用 golang.org/x/text/encoding 演示转换(需 go get)
/*
encoder := encoding.Windows1252.NewEncoder() // 示例:若目标打印机支持 CP1252
encoded, _ := encoder.String(text)
n, err := p.Write([]byte(encoded))
*/
// ✅ 更稳妥做法:使用系统默认 OEM 编码(GetOEMCP),或指定打印机支持的代码页
// 实际部署前请确认打印机驱动是否支持 UTF-8 直通(少数现代打印机支持),否则必须转码
n, err := p.Write([]byte(text))
if err != nil {
return fmt.Errorf("failed to write to printer: %w", err)
}
fmt.Printf("Successfully sent %d bytes to printer\n", n)
return nil
}
func main() {
msg := "Hello, 你好,Printer!\nThis is monospace text.\nLine 3."
if err := printToDefault(msg); err != nil {
log.Fatal(err)
}
}
关键注意事项: