事情是这样的,在一个项目中,我需要读取系统中的某个文件的创建时间,根据时间做不同的处理,如超过一定时间后就删除掉。 查询了一下,获取文件创建时间可以使用标准库中的os 和 syscall 来完成,但是syscall该库在不同的系统中的接口是不一样的,如在Mac下是这样使用的
package main
import (
"fmt"
"os"
"syscall"
)
func main() {
f, _ := os.Stat("1.txt")
fattr, _ := f.Sys().(*syscall.Stat_t)
fmt.Println(fattr.Ctimespec.Sec)
}
使用FileInfo.Sys() 返回的是一个接口类型,这个接口类型在不同的系统是不一样的,func (fs.FileInfo).Sys() interface{}
在Linux和Mac中是 *syscall.Stat_t
,在windows中是*syscall.Win32FileAttributeData
,
之后再获取属性的时候性能参数也不一样。。。
上面的代码是linux中是这样的
package main
import (
"fmt"
"os"
"syscall"
)
func main() {
f, _ := os.Stat("1.txt")
fattr, _ := f.Sys().(*syscall.Stat_t)
fmt.Println(fattr.Ctime.Sec )
}
在windows中又下下面的这样
package main
import (
"fmt"
"os"
"syscall"
)
func main() {
f, _ := os.Stat("1.txt")
fattr, _ := f.Sys().(*syscall.Win32FileAttributeData)
fmt.Println(fattr.CreationTime.Nanoseconds()/1e9)
}
如果要画一个图表示
上面的其实还不是麻烦的,只是在如果你在Mac上开发的,将来你的程序如果要在windows上运行的话,那么开的时候写上适合windows的代码,就会在ide上直接报错了,也无法直接编译。
此时需要使用交叉编译,比如需要编译一个运行在x64位的windows上,则可以使用以下编译命令
GOOS=windows GOARCH=amd64 go build main.go
就可以正常编译了。
但是一个新的问题就来了,如果我想要在linux上使用,则我需要修改代码,改成可以在linux上运行的,然后使用linux上的交叉编译命令GOOS=linux GOARCH=amd64 go build main.go
,Mac下还要修改代码,这样如果要生成不同的系统可执行文件,则就是不停的修改代码,有没有一种只编写一次的,不用反复修改的?
答案是有的,我们可以使用go:build 标签的方式
我们可以在文件头部添加 //go:build
标识来表示该文件在哪些系统和架构上进行编译
如我们可以单建一个util.go 文件,将获取文件创建时间函数单独抽出来写到这个util.go文件中,假设这里面的函数适用于Mac系统
//go:build darwin
package main
import (
"errors"
"os"
"syscall"
)
func GetCtime(path string) (int64, error) {
finfo, err := os.Stat(path)
if err != nil {
return 0, err
}
fattr, ok := finfo.Sys().(*syscall.Stat_t)
if !ok {
return 0, errors.New("获取文件属性失败")
}
return fattr.Ctimespec.Sec, nil
}
在最上面的添加一个tag, //go:build darwin
表示这个文件是在darwin 系统上编译使用的
此时我们就可以再创建两个文件,分别为util_linux.go, util_windows.go 文件 然后给它们设置build 标签
//go:build linux
package main
//go:build windows
package main
go:build 的逻辑关系
go:build 标签可以有逻辑关系的,比如我想要设置某个文件在darwin和liunx系统同时编译,可以使用
//go:build darwin || linux
也可以是且(AND)和或(OR)的关系混合
//go:build (darwin && amd64) || linux
自定义标签
除了GOOS和GOARCH,我们也可以自定义一些标签,如dev,release
//go:build dev
那么在编译文件的时候,就可以使用 go build -tags "dev" .
, 则就可以使用带有dev 编译标签的文件进行编译了。