297

在 nodejs 我使用__dirname。在 Golang 中这个等价物是什么?

我用谷歌搜索并找到了这篇文章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"))

但这是在 Golang 中的正确方式还是惯用方式?

4

14 回答 14

369

编辑:从 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)
}
于 2013-08-30T16:18:13.090 回答
254

这应该这样做:

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)
}
于 2013-08-30T16:44:13.457 回答
69

使用包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)
}
于 2013-08-31T13:02:37.493 回答
13
filepath.Abs("./")

Abs 返回路径的绝对表示。如果路径不是绝对路径,它将与当前工作目录连接以将其转换为绝对路径。

如评论中所述,这将返回当前处于活动状态的目录。

于 2017-06-09T17:45:32.020 回答
12

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

filepath.EvalSymlinkshttps ://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)
}
于 2018-12-04T12:09:39.317 回答
10

如果您使用这种方式:

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

当您使用 GoLand 等 IDE 运行程序时,您将获得 /tmp 路径,因为可执行文件将保存并从 /tmp 运行

我认为获取当前工作目录或“。”的最佳方式 是 :

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

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

os.Getwd ()函数将返回当前工作目录。并且全部不使用任何外部库:D

于 2018-12-24T12:33:00.923 回答
7
dir, err := os.Getwd()
    if err != nil {
        fmt.Println(err)
    }

this is for golang version: go version go1.13.7 linux/amd64

works for me, for go run main.go. If I run go build -o fileName, and put the final executable in some other folder, then that path is given while running the executable.

于 2020-07-16T01:26:04.163 回答
6

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

在您想将它与 go run main.go 一起用于本地开发之前,这可以正常工作。不知道如何最好地解决这个问题,而无需每次都事先构建可执行文件。

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

我在使用其他编译器时遇到了这个问题,并且发现自己制作了这些实用程序,因为它们没有随编译器一起提供……尤其是像 C 这样的工具,你必须编译和链接然后运行它(工作量太大)。

如果有人喜欢我对 gorun.exe(或 elf)的想法,我可能会很快将其上传到 github..

抱歉,这个答案是作为评论的,但由于我的声誉还不够大,我无法发表评论。

或者,可以修改“go run”(如果它还没有此功能)以具有诸如“go run -notemp”之类的参数,以不在临时目录(或类似目录)中运行程序。但我更喜欢只输入 gorun 或“gor”,因为它比复杂的参数短。Gorun.exe 或 gor.exe 需要安装在与你的 go 编译器相同的目录中

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

于 2017-04-18T13:13:56.917 回答
6

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

package main

import (
    "fmt"
    "os"
)


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

    // or
    dir, _ := os.Getwd()
    fmt.Println(dir)
}
于 2019-02-14T20:50:48.577 回答
3

我从 Node.js 来到 Go。__dirname在 Go 中等效的 Node.js是:

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

此线程中的其他一些提及以及它们错误的原因:

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

最后,我建议不要为此用例引入第三方包。这是您可以使用的软件包:

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包的目录。

于 2021-12-27T04:07:58.283 回答
0

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

这是 goland 工程师Daniil 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"
)

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

于 2021-11-20T23:58:47.473 回答
0
// 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])
}
于 2021-10-09T03:14:01.700 回答
0

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

最好的答案是question itself这就是我如何找到file which is not in the main package.

_, filename, _, _ := runtime.Caller(1)
pwd := path.Dir(filename)
于 2021-12-09T12:12:09.863 回答
-3

Gustavo Niemeyer 的回答很棒。但在 Windows 中,运行时 proc 主要位于另一个目录中,如下所示:

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

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

于 2020-01-03T03:30:51.963 回答