背景

项目交叉编译为可执行文件之后,在其他目录执行文件时提示找不到配置文件

2020/03/14 20:44:23 配置文件读取失败 open config.ini: no such file or directory

解决方案

直接采用以下代码获取到实际执行文件的路径,然后拼接配置文件即可

file, _ := exec.LookPath(os.Args[0])
path, _ := filepath.Abs(file)
index := strings.LastIndex(path, string(os.PathSeparator))
path = path[:index]

代码分析

os.Args是用来获取命令行执行参数分片的,当使用go run

$ go run main.go
[/var/folders/3s/5v6r481x17x5ks_7q1dzmlsw0000gp/T/go-build231739964/b001/exe/main]

分片0会是一串复杂的路径,原因是直接run go文件时会将文件转移到临时路径下,然后再进行编译和执行,如果直接执行编译后的文件就不一样了,此时分片0为执行文件的相对路径

$ go build
$ ./jira_reminder
[./jira-reminder]

接下来看一下LookPath方法的作用,官方文档中是这样解释的

// LookPath searches for an executable named file in the
// directories named by the PATH environment variable.
// If file contains a slash, it is tried directly and the PATH is not consulted.
// The result may be an absolute path or a path relative to the current directory.

大致意思就是它会去环境变量中找这个可执行文件的绝对路径,或相对于当前目录的路径。接下来执行了filepath.Abs方法

// Abs returns an absolute representation of path.
// If the path is not absolute it will be joined with the current
// working directory to turn it into an absolute path. The absolute
// path name for a given file is not guaranteed to be unique.
// Abs calls Clean on the result.

意思是它会根据传入的路径计算出绝对路径,如果传入的为相对路径,那么它会把当前路径拼接上

此时返回的path是一个包含可执行文件在内的完整路径,我们只需要精确到目录即可

index := strings.LastIndex(path, string(os.PathSeparator))

以上代码会搜索最后一个目录分隔符的位置(下标),然后通过以下代码将路径中下标后面的字符串切割掉

path = path[:index]

这样就完成了目录的获取,接下来再拼接上我们实际的配置文件就可以了

番外

发现不调用exec.LookPath也是可以达到查询绝对路径的目的的,那么exec.LookPath还有什么用?

path, _ := filepath.Abs(os.Args[0])
index := strings.LastIndex(path, string(os.PathSeparator))
path = path[:index]

我们来看一下源码,exec.LookPath的作用是从相对路径或环境变量PATH中递归找可执行文件,这起着一个校验的作用,检测调用的可执行文件是不是真的存在,如果存在再继续往下拼接出绝对路径,因为我们的执行文件的确是存在的,所以就算不使用exec.LookPath也可以达到目的

func LookPath(file string) (string, error) {
// NOTE(rsc): I wish we could use the Plan 9 behavior here
// (only bypass the path if file begins with / or ./ or ../)
// but that would not match all the Unix shells. if strings.Contains(file, "/") {
err := findExecutable(file)
if err == nil {
return file, nil
}
return "", &Error{file, err}
}
path := os.Getenv("PATH")
for _, dir := range filepath.SplitList(path) {
if dir == "" {
// Unix shell semantics: path element "" means "."
dir = "."
}
path := filepath.Join(dir, file)
if err := findExecutable(path); err == nil {
return path, nil
}
}
return "", &Error{file, ErrNotFound}
}

最新文章

  1. iOS学习32之UIKit框架-可视化编程-XIB
  2. Log4J简单使用
  3. CharsetUtils.java
  4. Task和BackTask
  5. WCF配置文件全攻略
  6. Java出现No enclosing instance of type E is accessible. Must qualify the allocation with an enclosing--转
  7. ORA-32001: write to SPFILE requested but no SPFILE specified at startup
  8. html5+css3实现上拉和下拉刷新
  9. bzoj1311: 最优压缩
  10. [React] React Router: Redirect
  11. Mac os 进行Android开发笔记(2)
  12. css单位总结
  13. Spark算子--distinct
  14. Linux-Shell编程之求命令行中所有整数之和
  15. web安全之机器学习入门——3.1 KNN/k近邻
  16. JDK8新特性02 Lambda表达式02_Lambda语法规则
  17. Mysql数据库配置参数详解大全
  18. mybatis-高级结果映射之一对一
  19. Java多线程系列——线程阻塞工具类LockSupport
  20. gerrit设置非小组成员禁止下载代码

热门文章

  1. 70)PHP,cookie的安全传输和HTTPonly
  2. python学习笔记(7)数据类型转换
  3. smarty应用1 之 模板进行数学运算,保留小数位数
  4. 吴裕雄--天生自然HTML学习笔记:HTML 链接
  5. 吴裕雄--天生自然 R语言开发学习:回归(续三)
  6. 自然语言分析工具Hanlp依存文法分析python使用总结(附带依存关系英文简写的中文解释)
  7. 环境安装文档(for Ubuntu)
  8. celery beat之pidfile already exists问题
  9. 【系统篇】Archlinux系统安装
  10. 4——PHP比较&&复制运算符