使用Golang编写Windows小工具
2023-05-10
这段代码是一个用于将派工明细文件同步到MES系统的程序插件。它包含了一些结构体和方法,用于处理文件上传和解析HTTP响应。在main函数中,程序首先获取当前目录并读取配置文件。然后,它遍历指定目录下的文件,找到当天发生变动的派工明细文件。接下来,程序使用多线程并发地读取文件,并将文件内容上传到MES系统。最后,程序解析MES系统的响应,并打印出相应的信息。
简介
派工明细文件同步是将派工明细文件上传到MES系统的过程。派工明细文件包含了产品的详细信息,如产品型号、数量和生产日期等。将这些信息同步到MES系统中可以实现生产数据的实时更新和管理。 派工明细文件同步的重要性在于:
- 数据准确性:通过将派工明细文件同步到MES系统,可以确保生产数据的准确性。这有助于避免人工输入错误和数据不一致的问题。
- 实时更新:派工明细文件同步可以实现生产数据的实时更新。这意味着生产部门和其他相关部门可以及时获取最新的生产数据,以便做出准确的决策。
- 数据分析:将派工明细文件同步到MES系统后,可以对生产数据进行更深入的分析。通过对数据的统计和分析,可以发现生产过程中的潜在问题,并采取相应的措施进行改进。
- 效率提升:派工明细文件同步可以提高生产过程的效率。通过自动化的文件上传和数据更新,可以减少人工操作的时间和错误,提高生产效率。 综上所述,派工明细文件同步对于实现生产数据的准确性、实时更新和数据分析具有重要意义。它可以提高生产过程的效率,并为企业的决策提供准确的数据支持。
代码编写
结构体和方法:
- Config:用于存储配置信息的结构体,包括MES站点地址、扫描文件路径、派工上传人和是否覆盖数据。
- Multipart:用于处理文件上传的结构体。
- CreateFormFile方法:用于创建表单文件并将文件内容复制到表单中。
- CreateFormField方法:用于创建表单字段并将字段值写入表单中。
- ParseResponse函数:用于解析HTTP响应并返回结果。
主函数步骤:
- 获取当前目录和配置文件。
- 读取配置文件,并解析为Config结构体。
- 遍历指定目录下的文件,找到当天发生变动的派工明细文件。
- 并发地读取文件并将文件内容上传到MES系统。
- 解析MES系统的响应并打印相应的信息。
结果解析步骤:
- 读取响应体的内容。
- 使用json.Unmarshal函数将响应体解析为map[string]interface{}类型的结果。
- 返回解析结果和可能的错误。
交叉编译
编译成windows环境exe可执行文件过程,打开文件所在目录,使用以下命令进行交叉编译并生成 Windows 可执行文件。其中,GOOS 环境变量设置为 windows 表示目标操作系统为 Windows,GOARCH 环境变量设置为 amd64 表示目标处理器架构为 64 位。GOOS=windows GOARCH=amd64 go build -o MesUploader.exe
这将会在当前目录下生成一个名为 MesUploader.exe 的 Windows 可执行文件。
现在你可以将生成的 MesUploader.exe 文件拷贝到 Windows 系统上运行。
请注意,在进行交叉编译时,需要使用目标操作系统和处理器架构相关的环境变量来告诉 Go 编译器生成相应的可执行文件。以上示例中使用了 GOOS=windows 和 GOARCH=amd64 来生成适用于 Windows 的 64 位可执行文件。可以根据需要调整这些环境变量以满足你的要求。
总结
通过本文,学习了如何使用Go语言编写一个派工明细文件同步程序插件。了解了如何读取配置文件、遍历文件、并发上传文件,并解析MES系统的响应。这个插件可以帮助实现派工明细文件的同步,提高工作效率。
完整代码
package main
import (
"bytes"
"encoding/json"
"fmt"
"github.com/gookit/color"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"os"
"path/filepath"
"sync"
"time"
)
type Config struct {
ApiUrl string `json:"MES站点地址"`
FileDir string `json:"扫描文件路径"`
CreateUser string `json:"派工上传人"`
UpdateSupport string `json:"是否覆盖数据"`
}
type Multipart struct {
FilePath string
}
func (m *Multipart) CreateFormFile(writer *multipart.Writer) error {
file, err := os.Open(m.FilePath)
if err != nil {
color.Redp("读取文件失败:", err)
return err
}
defer file.Close()
part, err := writer.CreateFormFile("file", filepath.Base(m.FilePath))
if err != nil {
color.Redp("创建表单文件失败:", err)
return err
}
if err != nil {
color.Redp("写入表单数据失败:", err)
return err
}
_, err = io.Copy(part, file)
if err != nil {
color.Redp("复制文件失败:", err)
return err
}
return nil
}
func (m *Multipart) CreateFormField(writer *multipart.Writer, user string, updateSupport string) error {
fileWriter2, err := writer.CreateFormField("userName")
if err != nil {
return err
}
_, errs2 := fileWriter2.Write([]byte(user))
if errs2 != nil {
return errs2
}
fileWriter3, err := writer.CreateFormField("updateSupport")
if err != nil {
return err
}
_, errs3 := fileWriter3.Write([]byte(updateSupport))
if errs3 != nil {
return errs2
}
return nil
}
func ParseResponse(response *http.Response) (map[string]interface{}, error) {
var result map[string]interface{}
body, err := ioutil.ReadAll(response.Body)
if err == nil {
err = json.Unmarshal(body, &result)
}
return result, err
}
func main() {
// 获取当前目录
dir, err := os.Getwd()
if err != nil {
color.Redp("获取当前目录失败:", err)
fmt.Scanf("h")
return
}
// 读取配置文件
configFile, err := os.Open(filepath.Join(dir, "config.json"))
if err != nil {
color.Error.Println("读取config.json配置文件失败:", err)
fmt.Scanf("h")
return
}
defer configFile.Close()
// 解析配置文件
var config Config
err = json.NewDecoder(configFile).Decode(&config)
if err != nil {
color.Error.Println("解析配置文件config.json失败:", err)
fmt.Scanf("h")
return
}
fmt.Println("")
fmt.Println("===========MES-派工明细-同步程序插件================")
fmt.Printf("当前MES站点地址:%s \t文件扫描路径:%s \t上传人配置:%s \n", config.ApiUrl, config.FileDir, config.CreateUser)
fmt.Println("===========================================")
color.Info.Prompt("注意:只会读取" + config.FileDir + "目录下当天发生文件变动的文件\n")
fmt.Println("===========================================")
// 遍历目录下的所有文件
files, err := ioutil.ReadDir(config.FileDir)
if err != nil {
color.Error.Println("读取"+config.FileDir+"目录失败:", err)
fmt.Scanf("h")
return
}
// 先打印出当前目录最后改动日期为当天的文件列表,之后进行列表批量上传
todayFiles := make([]string, 0)
for _, file := range files {
if !file.IsDir() && file.ModTime().Day() == time.Now().Day() {
switch filepath.Ext(file.Name()) {
case ".xlsx", ".xls":
filePath := filepath.Join(config.FileDir, file.Name())
color.Greenp("找到当天变动文件:" + filePath + "\n")
todayFiles = append(todayFiles, filePath)
}
}
}
fmt.Println("===========================================")
if len(todayFiles) == 0 {
color.Danger.Prompt("没有找到当天文件改动的派工明细文件,支持的导入EXCEL格式为:xlsx,xls\n")
fmt.Scanf("h")
return
}
var wg sync.WaitGroup
for _, filePath := range todayFiles {
wg.Add(1)
go func(filePath string) {
defer wg.Done()
fmt.Println("正在读取文件:", filePath)
file, err := os.Open(filePath)
if err != nil {
fmt.Println("读取文件失败:", err)
fmt.Scanf("h")
return
}
defer file.Close()
var resp *http.Response
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
m := &Multipart{FilePath: filePath}
errCreateFormFile := m.CreateFormFile(writer)
if errCreateFormFile != nil {
return
}
isUpdate := '0'
if config.UpdateSupport == "是" {
isUpdate = '1'
}
errCreateFormFile = m.CreateFormField(writer, config.CreateUser, string(isUpdate))
if errCreateFormFile != nil {
return
}
err = writer.Close()
if err != nil {
fmt.Println("关闭表单文件失败:", err)
fmt.Scanf("h")
return
}
resp, err = http.Post(config.ApiUrl+"/pms/productDispatchDetails/golangApi", writer.FormDataContentType(), body)
if err != nil {
fmt.Println("上传文件失败:", err)
fmt.Println("-----------------------")
fmt.Scanf("h")
return
}
ResponseBackMap, _ := ParseResponse(resp)
if ResponseBackMap["code"] == float64(200) {
color.Greenln(ResponseBackMap["msg"])
} else {
color.Danger.Println(ResponseBackMap["msg"])
}
defer resp.Body.Close()
fmt.Println("-----------------------")
}(filePath)
}
wg.Wait()
color.Success.Prompt("所有文件同步MES系统完成~,请注意提示信息,正确则可以关闭程序窗口\n")
fmt.Scanf("h")
}