前言
青训营抖音项目投稿视频需要在服务端生成封面文件,中间需要将文件暂存,为保证程序的健壮性,需要在不同环境下都可以稳定运行,而不同环境下的文件路径不同,主要是windows盘符路径与Linux不同,所以需要保证兼容。
两种启动方式带来的问题
用Go编写的程序有两种执行方式,go run和go build,通常的做法是go run用于本地开发,用一个命令中快速测试代码确实非常方便;在部署生产环境时,我们会通过go build构建出二进制文件然后上传到服务器再去执行。
但是,如果我们使用os.Executable()直接获取路径则会出现问题。
由于go run会将源代码编译到系统TEMP或TMP环境变量目录中并启动执行;而go build只会在当前目录编译出可执行文件,并不会自动执行。go run main.go等价于go build & ./main,此时go run获取到的路径是错误的。
查阅资料,runtime.Caller()可以正确的获取不同启动方式的路径,但是如果在Windiws构建好项目,使用Linux启动项目则又会出现问题:Linux中启动会打印Windows下的路径。
解决方案
go run可以通过runtime.Caller()获取到正确的结果
go build可以通过 os.Executable()来获取到正确的路径
我们可以在程序中对比os.Executable()获取到的路径是否与环境变量TEMP设置的路径相同, 如果相同,说明是通过go run启动的,因为当前执行路径是在TEMP目录;不同的话则是go build的启动方式。
最终代码如下:
func GetCurrentAbPath() string {
dir := getCurrentAbPathByExecutable()
tmpDir, _ := filepath.EvalSymlinks(os.TempDir())
if strings.Contains(dir, tmpDir) {
return getCurrentAbPathByCaller()
}
return dir
}
// 获取当前执行文件绝对路径
func getCurrentAbPathByExecutable() string {
exePath, err := os.Executable()
if err != nil {
log.Fatal(err)
}
res, _ := filepath.EvalSymlinks(filepath.Dir(exePath))
return res
}
// 获取当前执行文件绝对路径(go run)
func getCurrentAbPathByCaller() string {
var abPath string
_, filename, _, ok := runtime.Caller(0)
if ok {
abPath = path.Dir(filename)
}
return abPath
}