当前位置: 首页 > 科技观察

Go:如何获取项目根目录?

时间:2023-03-16 11:05:21 科技观察

大家好,我是polarisxu。在项目中,尤其是Web项目中,经常需要获取项目的根目录,进而访问与项目相关的其他资源,如配置文件、静态资源文件、模板文件、数据文件、日志文件等。(Go1.16之后,有些可以通过embed轻松嵌入)。例如下面的目录结构:(路径为/Users/xuxinhua/stdcwd)├──bin├──cwd├──main.go└──log├──error.log为了正确读取error.log,我们需要获取项目根目录。学习了本文的知识后,这个问题就可以解决了。解决方案有很多种,各有优缺点和使用注意事项,选择自己喜欢的就可以了。01使用os.GetwdGo语言标准库os有一个Getwd函数:funcGetwd()(dirstring,errerror)返回当前工作目录。基于此,我们可以得到项目的根目录。还是上面的目录结构,切换到/Users/xuxinhua/stdcwd,然后执行程序:$cd/Users/xuxinhua/stdcwd$bin/cwd此时当前目录(os.Getwd的返回值)为/用户/xuxinhua/stdcwd.但是,如果我们不在这个目录下执行bin/cwd,那么当前目录就会改变。因此,这不是一个好办法。但是我们可以要求程序必须运行在/Users/xuxinhua/stdcwd目录下,否则会报错。怎么限制就留给你自己想了。02使用exec.LookPath在上面的目录结构中,如果我们能拿到程序cwd所在的目录,就相当于拿到了项目根目录。binary,err:=exec.LookPath(os.Args[0])os.Args[0]为当前程序名。如果我们在项目根目录下执行程序bin/cwd,上面程序返回的二进制结果为bin/cwd,这是程序cwd的相对路径,绝对路径可以通过filepath获取。abs()函数,最后通过两次调用filepath.Dir得到项目根目录。binary,_:=exec.LookPath(os.Args[0])root:=filepath.Dir(filepath.Dir(filepath.Abs??(binary)))03使用os.Executable可能类似的需求很常见,Goin1.8专门为这样的需求增加了一个函数://Executablereturnsthepathnamefortheexecutablethatstartedthecurrentprocess.//Thereisnoguaranteethatthepathisstillpointingtothecorrectexecutable.//Ifasymlinkwasusedtostarttheprocess,dependingontheoperatingsystem,theresultmightbethesymlinkorthepathitpointedto.//Ifastableresultisneeded,path/filepath.EvalSymlinksmighthelp.//Executablereturnsanabsolutepathunlessanerroroccurred.//Themainusecaseisfindingresourceslocatedrelativetoanexecutable.funcExecutable()(string,error)类似于exec.LookPath,但该函数返回的结果是绝对路径。因此,不需要对filepath.Abs??进行处理。binary,_:=os.Executable()root:=filepath.Dir(filepath.Dir(binary))注意exec.LookPath和os.Executable的结果是可执行程序的路径,包括可执行程序本身,如/Users/xuxinhua/stdcwd/bin/cwd细心的读者可能会注意到函数注释中提到的符号链接问题。为了获得稳定的结果,我们应该使用filepath.EvalSymlinks进行处理。packagemainimport("fmt""os""path/filepath")funcmain(){ex,err:=os.Executable()iferr!=nil{panic(err)}exPath:=filepath.Dir(ex)realPath,err:=filepath.EvalSymlinks(exPath)iferr!=nil{panic(err)}fmt.Println(filepath.Dir(realPath))}最终输出的是项目根目录。(如果你的可执行文件放在根目录下,最后的filepath.Dir就不需要了)注意:exec.LookPath也有软链接的问题。exec.LookPath和os.Executable函数,并提示你如果使用gorun运行,结果将是一个临时文件。所以,记得先编译(这也是比gorun更好的方式,gorun应该只用于本地测试)。04小结既然Go1.8给我们提供了这样的功能,那么对于本文提到的场景,我们应该始终使用它。