golang学习笔记(一)
编译
能否编译成静态exe,不需要go环境。
可以。使用命令:go build
使编译的exe有图标
- 安装rsrc
go get github.com/akavel/rsrc
go install github.com/akavel/rsrc
- 在go项目根目录下创建manifest文件, 命名随意,如:icon.manifest,内容为:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="1.0.0.0"
processorArchitecture="x86"
name="controls"
type="win32"
></assemblyIdentity>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
></assemblyIdentity>
</dependentAssembly>
</dependency>
</assembly>
- 把ico文件复制到go项目根目录下,如 myico.ico
- 执行命令,生成syso文件,名字可以随意。如main.syso
rsrc -manifest icon.manifest -ico myico.ico -o main.syso
- 执行
go build
即可生成带icon的exe,根目录下不能存在多个syso文件,否则build会报错。
跨平台编译(交叉编译)
- Mac下编译Linux, Windows平台的64位可执行程序:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build test.go
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build test.go
- Linux下编译Mac, Windows平台的64位可执行程序:
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build test.go
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build test.go
- Windows下编译Mac, Linux平台的64位可执行程序:
SET CGO_ENABLED=0
SET GOOS=darwin3
SET GOARCH=amd64
go build test.go
SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=amd64
go build test.go
GOOS:目标可执行程序运行操作系统,支持 darwin,freebsd,linux,windows
GOARCH:目标可执行程序操作系统构架,包括 386,amd64,arm
代码
如何读取及使用命令行参数
main函数不能使用参数。
命令行参数不像c#或者java是通过main(args[])这样来传递
- 通过
import "os"
,在程序中通过os.Args
可以获得一个[]string
类型的数组,其中第一个元素为可执行程序的绝对路径,其余为跟在其后的命令行参数。 - 可以使用
flag
模块来更方便的处理命令行参数。参考 https://studygolang.com/articles/3365
https://github.com/astaxie/gopkg/tree/master/flag
退出当前进程
import "os"
os.Exit(0)
解析文件路径
使用path
或者path/filepath
包来对路径进行解析。path/filepath
支持跨平台,所以推荐使用这个。
import "path/filepath"
// Split 将路径分解成两个字符串:路径和名称
// 其中name带后缀。
path, name := filepath.Split(file)
// Ext 获取文件后缀名(如果有),包含点号,如“.txt”
ext := filepath.Ext(file)
// 获取不带后缀名的文件名。包本身不带,用strings.TrimSuffix方法把后缀清除掉,
filenameWithoutExt := strings.TrimSuffix(name, ext)
获取时间
import "time"
//返回一个Time结构体
t := time.Now()
//utc时间戳,纳秒(毫秒的1/1e6)
t.UnixNano()
//utc时间戳,秒
t.Unix()
遍历目录
//此方法会遍历目录及子目录
filepath.Walk(dirpath, func(filename string, f os.FileInfo, err error) error {
if err != nil {
return err
}
if f.IsDir() {
log.Println(filename, "是文件夹")
} else {
log.Println(filename)
}
return nil
})
如果只要遍历当前目录,可以使用io/ioutil
包
dir, err := ioutil.ReadDir(dirPth)
for _, fi := range dir {
if fi.IsDir() { // 目录。这里可以进行递归
} else {
// 文件
}
}
控制多线程数量
go本身支持并发编程,通过runtime.GOMAXPROCS(n)
可以设置并发数,版本1.5以后默认开启并发,并发数与逻辑CPU数相同。
在调用方法前用关键字go
即可
如果调用了外部程序,在等待外部程序返回的时候,go会把CPU资源给别的协程使用,此时靠go的协程控制,可能会启用一堆的外部程序
package main
import (
"fmt"
"os/exec"
"runtime"
)
func main(){
//设置协程最大数为4
runtime.GOMAXPROCS(4)
//并发100个,执行run()来启动外部程序
//此处本来希望通过go控制,最多只有4个外部程序被调用。
//但是实际情况是,在等待外部程序返回的时候,go并没有阻塞协程,会继续调用run(),导致同时100个out.exe被启动
for i := 0; i < 100; i++ {
go run();
}
}
func run(){
//新建一个命令行 out.exe args1,此处假设程序需要运行30秒后才退出
cmd := exec.Command("out.exe", "args1")
//执行命令行并等待返回
cmd.Run()
}
等待所有线程退出
package main
import "fmt"
import "time"
import "sync"
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
time.Sleep(1 * time.Second)
fmt.Println(i)
}(i)
}
wg.Wait() // 等待
fmt.Println("main exist")
}
各种包
日志
简单日志可以使用log
包进行打印
import "log"
//设置日志打印的一些项目,这里指要在日志中包含日期和毫秒
log.SetFlags(log.Ldate | log.Lmicroseconds)
log.Println("这是一条日志")
执行外部程序
import "os/exec"
// 创建一个cmd命令,此时命令还没有执行
cmd := exec.Command("exe file path", args1,args2)
// 执行方式1。Run其实就是Start后再Wait
cmd.Run()
// 执行方式2。执行命令后立刻返回
cmd.Start()
// 执行方式3。执行命令,并等待外部程序退出后获得输出信息
output := cmd.Output()
log.Printf("%s",output)