Golang开发自动加载COM扫码枪进行一维码、二维码扫码与解码
1. 项目概述
本项目基于Golang语言开发,实现了自动检测、加载COM端口扫码枪设备,并对扫码数据进行读取、解码和处理的功能。该程序支持多种串口检测方式,自动识别不同编码格式的条码数据,并提供了高效的并发处理机制。
1.1 主要功能特点
- 自动扫描并识别系统中的COM端口设备
- 支持三种串口检测方式:第三方库、Windows注册表、WMI
- 自动识别扫码枪设备(支持YJ4600和NLDC M9型号)
- 支持UTF-8和GBK编码格式的自动检测与转换
- 采用协程实现高效的扫码数据并发处理
- 支持扫码数据的JSON解析与结构体转换
2. 技术栈与依赖
2.1 核心编程语言
- Golang 1.2.24.0
2.2 主要依赖库
| 依赖库 | 用途 |
|---|---|
github.com/go-ole/go-ole |
Windows COM接口操作,用于WMI查询 |
github.com/go-ole/go-ole/oleutil |
OLE自动化工具库 |
github.com/tarm/goserial |
串口通信操作 |
go.bug.st/serial |
第三方串口检测库 |
golang.org/x/sys/windows/registry |
Windows注册表操作 |
golang.org/x/text/encoding/simplifiedchinese |
中文编码转换 |
3. 系统架构与核心模块
3.1 系统架构图
scss
┌─────────────────────────────────────────────────────┐
│ 主程序入口 │
├────────────────┬────────────────┬───────────────────┤
│ 串口检测模块 │ 串口通信模块 │ 数据处理模块 │
├────────────────┼────────────────┼───────────────────┤
│ getCommlist2()│ serial.OpenPort()│ readBarcodeData() │
│ getCommList() │ s.Read() │ resolveBarcodeData() │
│ getCommListWmi()│ │ codeJsonConvertStruct() │
└────────────────┴────────────────┴───────────────────┘
│ │ │
└────────────────┼────────────────┘
▼
┌───────────────┐
│ 编码转换模块 │
├───────────────┤
│ GetStrCoding()│
│ isUtf8() │
│ isGBK() │
└───────────────┘
3.2 核心模块说明
3.2.1 串口检测模块
该模块负责检测系统中所有可用的COM端口,并识别扫码枪设备。提供了三种检测方式:
-
第三方库检测 (
getCommlist2())- 使用
go.bug.st/serial库直接获取端口列表 - 实现简单,但可能无法识别设备类型
- 使用
-
注册表检测 (
getCommList())- 通过读取Windows注册表
HARDWARE\DEVICEMAP\SERIALCOMM获取端口信息 - 支持识别特定型号的扫码枪(通过"youjie"关键词)
- 需要管理员权限运行
- 通过读取Windows注册表
-
WMI检测 (
getCommListWmi())- 使用Windows Management Instrumentation查询硬件信息
- 通过
Win32_PNPEntity类获取所有即插即用设备 - 支持识别多种型号的扫码枪(YJ4600和NLDC M9)
- 代码实现较为复杂,但功能强大
3.2.2 串口通信模块
负责与扫码枪设备建立连接并读取扫码数据:
- 使用
github.com/tarm/goserial库进行串口通信 - 支持配置波特率等串口参数
- 实现了持续的数据读取循环
- 处理读取错误和异常情况
3.2.3 数据处理模块
处理从扫码枪读取到的数据:
readBarcodeData(): 协程函数,持续接收并处理扫码数据resolveBarcodeData(): 解析条码数据,支持不同格式的条码codeJsonConvertStruct(): 将JSON格式的条码数据转换为结构体
3.2.4 编码转换模块
自动识别和转换不同编码格式的数据:
GetStrCoding(): 自动检测数据编码格式(UTF-8、GBK或未知)isUtf8(): UTF-8编码检测isGBK(): GBK编码检测- 支持UTF-8与GBK编码之间的双向转换
4. 核心功能实现细节
4.1 串口检测实现
4.1.1 WMI检测方式详解
WMI检测是最复杂但功能最强大的检测方式,其实现步骤如下:
- 初始化COM接口:
ole.CoInitialize(0) - 创建SWbemLocator对象:
oleutil.CreateObject("WbemScripting.SWbemLocator") - 获取IDispatch接口:
unknown.QueryInterface(ole.IID_IDispatch) - 连接WMI服务:
oleutil.CallMethod(wmi, "ConnectServer") - 执行WMI查询:
oleutil.CallMethod(service, "ExecQuery", "SELECT * FROM Win32_PNPEntity") - 遍历查询结果,筛选出COM端口设备
- 根据设备名称识别扫码枪型号
关键代码片段:
go
func getCommListWmi() ([]string, string) {
// 初始化COM接口
ole.CoInitialize(0)
defer ole.CoUninitialize()
// 创建WMI对象并执行查询
unknown, _ := oleutil.CreateObject("WbemScripting.SWbemLocator")
defer unknown.Release()
wmi, _ := unknown.QueryInterface(ole.IID_IDispatch)
defer wmi.Release()
serviceRaw, _ := oleutil.CallMethod(wmi, "ConnectServer")
service := serviceRaw.ToIDispatch()
defer service.Release()
resultRaw, _ := oleutil.CallMethod(service, "ExecQuery", "SELECT * FROM Win32_PNPEntity")
result := resultRaw.ToIDispatch()
defer result.Release()
// 遍历结果并筛选COM端口
// ...
}
4.2 扫码数据读取与处理
4.2.1 数据读取机制
程序通过持续循环从串口读取数据,并处理不同型号扫码枪的发送特性:
- 支持一次性发送完整数据的扫码枪(如YJ4600)
- 支持分多次发送数据的扫码枪(如NLDC M9)
- 使用缓冲区拼接完整的扫码数据
关键代码片段:
go
// 开启一个循环,持续读取扫码枪的数据
codeData := "" //用于保存每次读取到缓冲区的数据
for {
//清空缓冲区的数据
buf = make([]byte, 1024)
//读取码文数据到缓冲区内
lens, err := s.Read(buf)
if err != nil {
log.Println(err)
continue
}
// 将读取到的数据追加到codeData中,处理分多次发送的情况
x := buf[:lens]
codeData += string(x)
// 处理完整的扫码数据
if lens > 4 {
// 编码转换和处理
// ...
}
}
4.2.2 并发处理机制
程序使用Golang的协程特性实现了扫码数据的异步处理:
- 创建一个通道用于传递扫码数据
- 启动一个协程持续监听通道
- 主线程读取到完整数据后发送到通道
- 协程接收到数据后进行解析和处理
关键代码片段:
go
// 用于接收码文的通道
receiveMessage := make(chan string)
// 开启一个协程,不断从通道内读取数据
go readBarcodeData(receiveMessage)
// 读取到完整数据后发送到通道
if codeString != "" {
receiveMessage <- codeString
}
// 协程函数:持续读取通道内的码文数据
func readBarcodeData(message chan string) {
for {
select {
case data := <-message:
fmt.Printf("扫码时间:%v\n", time.Now().String())
//解析码文数据
resolveBarcodeData(data)
}
}
}
4.3 编码识别与转换
4.3.1 编码检测算法
程序实现了UTF-8和GBK编码的自动检测:
- UTF-8检测:根据UTF-8编码规则,检查字节序列是否符合格式
- GBK检测:检查双字节是否落在GBK编码范围内
- 检测顺序:先检测UTF-8,再检测GBK,确保准确性
关键代码片段:
go
func GetStrCoding(data []byte) string {
if isUtf8(data) == true {
return UTF8
} else if isGBK(data) == true {
return GBK
} else {
return UNKNOWN
}
}
4.3.2 编码转换实现
支持UTF-8与GBK编码之间的双向转换:
go
if GetStrCoding([]byte(codeData)) == "UTF8" {
// UTF-8转GBK再转UTF-8(处理特殊字符)
gbkData, _ := simplifiedchinese.GB18030.NewEncoder().Bytes([]byte(codeData))
utf8Data, _ := simplifiedchinese.GB18030.NewDecoder().Bytes(gbkData)
codeString = string(utf8Data)
}
if GetStrCoding([]byte(codeData)) == "GBK" {
// GBK转UTF-8
b, _ := simplifiedchinese.GB18030.NewDecoder().Bytes([]byte(codeData))
codeString = string(b)
}
4.3.3 运行效果
go
(TraeAI-8) D:\vfptest [1:1] $ go run test_com.go
蓝牙链接上的标准串行 (COM4)
蓝牙链接上的标准串行 (COM5)
Bluetooth Device (RFCOMM Protocol TDI)
本机串口列表:[蓝牙链接上的标准串行 (COM4) 蓝牙链接上的标准串行 (COM5) Bluetooth Device (RFCOMM Protocol TDI)]
扫码枪:
端口被占用
2025/12/08 13:23:17 The system cannot find the path specified.
exit status 1
(TraeAI-8) D:\vfptest [1:1] $ go run test_com.go
YJ4600 (COM7)
strComName: YJ4600 (COM7
本机串口列表:[YJ4600 (COM7)]
扫码枪:COM7
-----------------------------------------------------------------------------------
--扫岗位证带中文
lens: 6
before convert: ������
codeData: ������
before convert: 6
coding: GBK
扫码时间:2025-12-08 13:26:26.7199849 +0800 CST m=+4.979774801
------------------------
码文: 李四▲
---------------------------------------------------------------------------------------------
--扫药品包装条码
------------------------
lens: 20
before convert: 88281800136707328258
codeData: 88281800136707328258
before convert: 20
coding: UTF8
after convert: 88281800136707328258
扫码时间:2025-12-08 13:27:05.295828 +0800 CST m=+43.555617901
------------------------
码文: 88281800136707328258
---------------------------------------------------------------------------------------------
--扫微信二维码
lens: 43
before convert: http://weixin.qq.com/r/9XUCGmDEOT1GrSR59yDn
codeData: http://weixin.qq.com/r/9XUCGmDEOT1GrSR59yDn
before convert: 43
coding: UTF8
after convert: http://weixin.qq.com/r/9XUCGmDEOT1GrSR59yDn
扫码时间:2025-12-08 13:27:23.5772834 +0800 CST m=+61.837073301
------------------------
码文: http://weixin.qq.com/r/9XUCGmDEOT1GrSR59yDn
---------------------------------------------------------------------------------------------
--扫半成品二维码带中文
lens: 380
before convert: D181��67010-AT��FD181-661-12��EM41��FLRY��0.5�����̡�690��300��15574��CC64������4����־ǿ��2016/12/21��ҹ����50��������20170102����4��X-F4��2016.11.10���۱���3��968221-1(TE)��0.5����DJ628-4.8��0.8A(ZJZ)��0.5����3.5��TE0.85����0.05mm��TE1.54����0.10mm��4.0��ZJZ1.15����0.05mm��ZJZ2.23����0.10mm��80��80������0.98��0.25��0.05+0.40��11��2/5��2��11��2/5��2������03-1-149-029�����Ǿ���
codeData: D181��67010-AT��FD181-661-12��EM41��FLRY��0.5�����̡�690��300��15574��CC64������4����־ǿ��2016/12/21��ҹ����50��������20170102����4��X-F4��2016.11.10���۱���3��968221-1(TE)��0.5����DJ628-4.8��0.8A(ZJZ)��0.5����3.5��TE0.85����0.05mm��TE1.54����0.10mm��4.0��ZJZ1.15����0.05mm��ZJZ2.23����0.10mm��80��80������0.98��0.25��0.05+0.40��11��2/5��2��11��2/5��2������03-1-149-029�����Ǿ���
before convert: 380
coding: GBK
扫码时间:2025-12-08 13:28:16.4129887 +0800 CST m=+114.672778601
------------------------
码文: D181■67010-AT■FD181-661-12■EM41■FLRY■0.5■黄绿■690■300■15574■CC64■下料4■高志强■2016/12/21■夜班■50■■■■20170102■分4■X-F4■2016.11.10■邵兵■3■968221-1(TE)■0.5■■DJ628-4.8×0.8A(ZJZ)■0.5■■3.5■TE0.85■±0.05mm■TE1.54■±0.10mm■4.0■ZJZ1.15■±0.05mm■ZJZ2.23■±0.10mm■80■80■■■0.98±0.25■0.05+0.40■11±2/5±2■11±2/5±2■■■03-1-149-029■■非军车
5. 代码优化与最佳实践
5.1 资源管理
- 使用
defer语句确保资源及时释放 - 对WMI对象操作添加空值检查,避免空指针异常
- 在循环中及时释放不再使用的对象
5.2 错误处理
- 实现了完善的错误处理机制
- 对可能失败的操作(如串口打开、数据读取)进行错误捕获和处理
- 提供友好的错误提示信息
5.3 并发安全
- 使用通道实现协程间的安全通信
- 避免共享变量的直接访问,减少竞态条件
5.4 性能优化
- 使用缓冲区拼接数据,减少字符串操作开销
- 采用协程并发处理,提高系统响应速度
- 实现了高效的编码检测算法
6. 使用说明
6.1 编译与运行
在项目目录下执行以下命令进行编译:
bash
go build -o test_com.exe test_com.go
运行程序:
bash
. est_com.exe
6.2 端口占用处理
如果遇到端口被占用的情况,可以使用以下命令查看和终止占用进程:
-
查看端口占用情况:
bashnetstat -aon|findstr "端口号" -
查看占用端口的进程:
bashtasklist|findstr "进程ID" -
终止占用进程:
bashtaskkill /f /t /im 进程名称
7. 总结与展望
本项目成功实现了基于Golang的COM扫码枪自动加载与扫码解码功能,具有以下优势:
- 跨型号兼容:支持多种不同型号的扫码枪设备
- 自动适配:自动识别系统中的COM端口和扫码枪设备
- 编码灵活:支持多种编码格式的自动检测与转换
- 高效处理:采用协程实现并发数据处理,提高系统性能
未来可以进一步扩展的功能包括:
- 支持更多类型的条码解码(如二维码、RFID等)
- 实现图形化界面,方便用户操作
- 增加数据持久化功能,支持扫码记录的存储和查询
- 扩展支持Linux等其他操作系统
8. 附录
8.1 主要数据结构
go
// 扫码数据结构体
type CodeData struct {
Xsxh string `json:"xsxh"`
Tzsh string `json:"tzsh"`
Xh string `json:"xh"`
Clgg string `json:"clgg"`
Ys string `json:"ys"`
Scrq string `json:"scrq"`
Bc string `json:"gc"`
Hddh string `json:"hddh"`
Xsgx string `json:"xsgx"`
Bz string `json:"gz"`
Dz1 string `json:"dz1"`
Ys1 string `json:"ys1"`
Dz2 string `json:"dz2"`
Ys2 string `json:"ys2"`
Cpfl string `json:"cpfl"`
}
8.2 关键常量定义
go
const (
GBK string = "GBK"
UTF8 string = "UTF8"
UNKNOWN string = "UNKNOWN"
)