Go语言向共享网络打印机打印报错,求替代CMD的实现方案
网络共享打印机的Go实现问题与解决
场景与问题描述
我有一台网络共享打印机,可通过CMD命令行执行以下命令完成打印:
echo hello > \\PSNHP\PRN // 或 copy /b hello.txt \\PSNHP\PRN
这种方法无需安装Windows驱动,十分实用。
我尝试用Go语言实现相同功能,代码如下:
socket, err = os.OpenFile("\\\\"+comp+"\\PRN", os.O_WRONLY, os.ModeNamedPipe) // 或 socket, err = os.Open("\\\\"+comp+"\\PRN")
但运行时报错:
open \\PSNHP\PRN: The system cannot find the file specified.
我有两个疑问:
- 网络打印机是否属于文件?
- CMD的流重定向是如何识别它的?
另外我了解到C#也存在同类问题,但现有解决方案无法满足需求——我无法直接访问打印机所在网络。
原理解析
网络打印机的本质
网络共享打印机不是磁盘上的实体文件,但Windows的SMB网络共享机制会将打印机的打印队列映射为\\主机名\PRN形式的命名管道(Named Pipe),这是一种进程间通信(IPC)通道,用于在网络上传输打印数据。
CMD重定向的工作逻辑
CMD的流重定向(>)和copy命令在处理\\主机\PRN路径时,会调用Windows系统的SMB客户端API,自动识别这是指向打印机的命名管道,而非普通文件路径,从而将数据流直接发送到打印机的打印队列中。而Go语言标准库的os.OpenFile/os.Open是通用文件操作接口,默认仅处理本地文件或本地命名管道,无法识别SMB网络共享的打印机管道,这就是报错的核心原因。
Go语言实现方案
方案1:调用Windows系统命令(简单直接)
借助Go的os/exec包调用CMD的copy命令,复用系统自带的SMB处理逻辑,无需额外依赖:
package main import ( "os/exec" ) func main() { comp := "PSNHP" filePath := "hello.txt" // 执行copy /b命令发送文件到打印机 cmd := exec.Command("cmd", "/c", "copy", "/b", filePath, "\\\\"+comp+"\\PRN") if err := cmd.Run(); err != nil { panic(err) } }
方案2:纯Go实现(使用SMB客户端库)
如果需要不依赖CMD的纯Go实现,可以使用第三方SMB库连接打印机共享并写入数据。以下是使用SMB客户端库的示例:
package main import ( "io" "os" "github.com/hirochachacha/go-smb2" ) func main() { comp := "PSNHP" filePath := "hello.txt" // 初始化SMB拨号器,填写认证信息(如果共享需要权限) dialer := &smb2.Dialer{ Initiator: &smb2.NTLMInitiator{ User: "", Password: "", }, } // 连接SMB服务器(默认端口445) conn, err := dialer.Dial("tcp", comp+":445") if err != nil { panic(err) } defer conn.Close() // 挂载打印机共享(共享名为PRN) share, err := conn.Mount("PRN") if err != nil { panic(err) } defer share.Umount() // 打开打印管道并写入文件内容 printPipe, err := share.Create("", os.O_WRONLY) if err != nil { panic(err) } defer printPipe.Close() srcFile, err := os.Open(filePath) if err != nil { panic(err) } defer srcFile.Close() _, err = io.Copy(printPipe, srcFile) if err != nil { panic(err) } }
注意:使用该方案时需确保目标打印机支持SMB共享,并根据实际情况填写正确的认证信息。
内容的提问来源于stack exchange,提问作者Sam Washington
相关产品推荐
相关产品推荐

