如何获取当前运行文件的目录?

在nodejs中,我使用__dirname。在戈朗,这相当于什么?

我在谷歌上搜索并找到了这篇文章http://andrewbrookins.com/tech/golang-get-directory-of-the-current-file/。他在哪里使用下面的代码

_, filename, _, _ := runtime.Caller(1)
f, err := os.Open(path.Join(path.Dir(filename), "data.csv"))

但在戈朗,这是正确的方式还是惯用的方式?

276795 次浏览

编辑:从Go 1.8(2017年2月发布)开始,建议使用os.Executable:

func Executable() (string, error)

Executable返回启动当前进程的可执行文件的路径名。不能保证路径仍然指向正确的可执行文件。如果使用符号链接启动进程,则结果可能是符号链接或它所指向的路径,这取决于操作系统。如果需要稳定的结果,请输入path/filepath。EvalSymlinks可能会有所帮助。

要获得可执行文件的目录,可以使用path/filepath.Dir

例子:

package main


import (
"fmt"
"os"
"path/filepath"
)


func main() {
ex, err := os.Executable()
if err != nil {
panic(err)
}
exPath := filepath.Dir(ex)
fmt.Println(exPath)
}

旧的回答:

你应该能够使用os.Getwd

func Getwd() (pwd string, err error)

Getwd返回与当前目录对应的根路径名。如果可以通过多条路径(由于符号链接)到达当前目录,Getwd可能返回其中任何一条。

例如:

package main


import (
"fmt"
"os"
)


func main() {
pwd, err := os.Getwd()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println(pwd)
}

这应该做到:

import (
"fmt"
"log"
"os"
"path/filepath"
)


func main() {
dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
if err != nil {
log.Fatal(err)
}
fmt.Println(dir)
}

使用包osext

它提供了函数ExecutableFolder(),返回当前运行的可执行程序所在文件夹的绝对路径(对cron作业很有用)。它是跨平台的。

联机文档 .

package main


import (
"github.com/kardianos/osext"
"fmt"
"log"
)


func main() {
folderPath, err := osext.ExecutableFolder()
if err != nil {
log.Fatal(err)
}
fmt.Println(folderPath)
}

如果你使用osext by kardianos包,并且你需要在本地测试,就像Derek Dowling评论的那样:

这工作得很好,直到你想使用它去运行main。去 当地的发展。不知道该怎么解决这个问题

.

.

解决方案是创建一个gorun.exe实用程序,而不是使用gorun。gorun.exe实用程序将使用“go build”编译项目,然后立即在项目的正常目录中运行它。

我有这个问题与其他编译器,并发现自己制作这些实用程序,因为它们不附带编译器…特别是像C这样的工具,你必须编译和链接,然后运行它(太多的工作)。

如果有人喜欢我的gorun.exe(或elf)的想法,我可能很快就会把它上传到github。

对不起,这个答案是作为一个评论,但我不能评论,因为我还没有足够大的声誉。

或者,“go run”也可以被修改(如果它还没有这个特性的话),让它有一个像“go run -notemp”这样的参数来不在临时目录(或类似的目录)中运行程序。但我更喜欢输入gorun或“gor”,因为它比复杂的参数要短。Gorun.exe或Gorun.exe需要安装在与go编译器相同的目录中

实现gorun.exe(或gorun.exe)将是微不足道的,因为我只用了几行代码就用其他编译器完成了…(著名的遗言;-)

filepath.Abs("./")

Abs返回路径的绝对表示。如果路径不是 绝对会将它与当前工作目录连接起来转

如注释中所述,这将返回当前活动的目录。

os.Executable: https://tip.golang.org/pkg/os/#Executable

filepath.EvalSymlinks: https://golang.org/pkg/path/filepath/#EvalSymlinks

完整的演示:

package main


import (
"fmt"
"os"
"path/filepath"
)


func main() {
var dirAbsPath string
ex, err := os.Executable()
if err == nil {
dirAbsPath = filepath.Dir(ex)
fmt.Println(dirAbsPath)
return
}


exReal, err := filepath.EvalSymlinks(ex)
if err != nil {
panic(err)
}
dirAbsPath = filepath.Dir(exReal)
fmt.Println(dirAbsPath)
}

如果你用这种方式:

dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
if err != nil {
log.Fatal(err)
}
fmt.Println(dir)

当你使用一些IDE(如GoLand)运行程序时,你会得到/tmp路径,因为可执行文件将从/tmp保存和运行

我认为获取当前工作目录或'的最佳方法。’是:

import(
"os"
"fmt"
"log"
)


func main() {
dir, err := os.Getwd()
if err != nil {
log.Fatal(err)
}
fmt.Println(dir)
}
os.Getwd ()函数将返回当前工作目录。 D

有时这就足够了,第一个参数总是文件路径

package main


import (
"fmt"
"os"
)




func main() {
fmt.Println(os.Args[0])


// or
dir, _ := os.Getwd()
fmt.Println(dir)
}
Gustavo Niemeyer的回答很好。 但在Windows中,runtime proc大多在另一个目录中,比如:

"C:\Users\XXX\AppData\Local\Temp"

如果您使用相对文件路径,如"/config/api.yaml",这将使用您的代码存在的项目路径。

dir, err := os.Getwd()
if err != nil {
fmt.Println(err)
}

这是为golang版本:go version go1.13.7 linux/amd64

为我工作,为go run main.go。如果我运行go build -o fileName,并将最终可执行文件放在其他文件夹中,则在运行可执行文件时给出该路径。

// GetCurrentDir
func GetCurrentDir() string {
p, _ := os.Getwd()
return p
}
// GetParentDir
func GetParentDir(dirctory string) string {
return substr(dirctory, 0, strings.LastIndex(dirctory, "/"))
}
func substr(s string, pos, length int) string {
runes := []rune(s)
l := pos + length
if l > len(runes) {
l = len(runes)
}
return string(runes[pos:l])
}

这里没有一个答案对我有用,至少在go version go1.16.2 darwin/amd64上。这是唯一接近node中的__dirname功能的东西

这是由黄金工程师daniel Maslov在jetbrains论坛上发布的

粘贴在下面以方便阅读:


这个技巧实际上非常简单,就是获取当前正在执行的对象,并将..添加到项目根目录。

创建一个类似testing_init.go的新目录和文件,包含以下内容:

package testing_init


import (
"os"
"path"
"runtime"
)


func init() {
_, filename, _, _ := runtime.Caller(0)
dir := path.Join(path.Dir(filename), "..")
err := os.Chdir(dir)
if err != nil {
panic(err)
}
}


之后,只需将包导入到任何测试文件中:


package main_test


import (
_ "project/testing_init"
)


现在您可以从项目根目录指定路径

如果你的文件不在main package中,那么上面的答案将不起作用 我尝试了不同的方法来找到当前运行文件的目录,但失败了

最好的答案是在question itself中,这就是我如何找到file which is not in the main package的当前工作目录。

_, filename, _, _ := runtime.Caller(1)
pwd := path.Dir(filename)

我从Node.js转到Go。在Go中等价于__dirname的Node.js是:

_, filename, _, ok := runtime.Caller(0)
if !ok {
return errors.New("unable to get the current filename")
}
dirname := filepath.Dir(filename)

这篇文章中提到的其他内容以及它们错误的原因:

  • os.Executable()将为您提供当前运行的可执行文件的文件路径。这相当于Node中的process.argv[0]。如果你想要获取子包的__dirname,这是不正确的。
  • os.Getwd()会给你当前的工作目录。这相当于Node中的process.cwd()。当您从另一个目录运行程序时,这将是错误的。

最后,我建议不要为这个用例引入第三方包。这里有一个你可以使用的包:

package current


// Filename is the __filename equivalent
func Filename() (string, error) {
_, filename, _, ok := runtime.Caller(1)
if !ok {
return "", errors.New("unable to get the current filename")
}
return filename, nil
}




// Dirname is the __dirname equivalent
func Dirname() (string, error) {
filename, err := Filename()
if err != nil {
return "", err
}
return filepath.Dir(filename), nil
}

注意,我已经将runtime.Caller(1)调整为1,因为我们想获取调用current.Dirname()的包的目录,而不是包含current包的目录。

不要使用&;__abc1 &;runtime.Caller(0)

当你go buildgo install一个程序时,这是有效的,因为你正在重新编译它。

但是当你在你同事的工作站上(他们没有Go,只需要可执行文件)go build一个程序然后进行分配(副本)时,runtime.Caller(0)的结果将是你构建它的路径(从你的计算机)。
即在他们自己的计算机上可能存在的路径

os.Args[0]或更好的os.Executable()(提到在这里)和kardianos/osext(提到在这里在这里)更可靠。