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

eka*_*nna 213 go

在nodejs中,我使用__dirname.在Golang中相当于什么?

我用Google搜索并发现了这篇文章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"))
Run Code Online (Sandbox Code Playgroud)

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

Int*_*net 256

编辑:从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)
}
Run Code Online (Sandbox Code Playgroud)

老答案:

你应该可以使用 os.Getwd

func Getwd() (pwd string, err error)
Run Code Online (Sandbox Code Playgroud)

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)
}
Run Code Online (Sandbox Code Playgroud)

  • 这是当前进程工作目录.在nodejs中它等同于process.cwd()http://nodejs.org/api/process.html#process_process_cwd (3认同)
  • "2017年2月发布"?似乎时间机器已经发明,我们有成员从未来发布.很高兴知道未来版本将拥有可靠的跨平台方法,与此同时我们必须坚持目前可用的解决方案. (3认同)
  • @ljgww 抱歉,我会带着我的 Delorean 回家:-) 我提前更新了我的答案,因为我刚刚看到了即将推出的功能,并认为我稍后会忘记更新答案。 (3认同)
  • 好的,我看到了区别.你是在filesytem中的二进制文件的位置(而不是当前的工作目录)后,我认为`runtime.Caller`是你最接近"惯用"的 (2认同)

Gus*_*yer 205

这应该这样做:

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)
}
Run Code Online (Sandbox Code Playgroud)

  • **这不是一种可靠的方式**,请参阅关于使用**xtxt**的答案,因为这是与我们在各种操作系统上的所有客户端一起工作的实现.我使用这种方法实现了代码,但似乎不太可靠,许多用户抱怨这种方法导致的错误选择了可执行文件的错误路径. (33认同)
  • 即使os.Args [0]不包含abs路径,它实际上也能工作.操场结果不符合您的预期是因为它位于沙箱内. (5认同)
  • 对我不起作用https://play.golang.org/p/c8fe-Zm_bH - os.Args [0]不一定包含abs路径. (4认同)
  • 在Windows上使用Go 1.6得到与emrah相同的结果(得到临时文件夹的路径而不是源文件夹).要在不使用任何外部依赖项的情况下获取源文件文件夹的路径,请使用OP的代码的轻微修改版本:`_,currentFilePath,_,_:= runtime.Caller(0)``dirpath:= path.Dir( currentFilePath)`(注意`runtime.Caller(0)`而不是`runtime.Caller(1)`) (3认同)
  • 这里有可能出现错误吗?如果是这样,出于好奇心,错误会是什么? (2认同)

Dob*_*ort 57

使用包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)
}
Run Code Online (Sandbox Code Playgroud)

  • 这是在Windows和Linux上为我产生预期结果的唯一答案. (12认同)
  • 这种方法很好,直到您想将它与`go run main.go`一起用于本地开发.不确定如何在不事先构建可执行文件的情况下最好地解决这个问题. (3认同)
  • @DerekDowling一种方式是先做一个`go install`,然后运行`go build -v*.go &&./ main`.`-v`会告诉你正在构建哪些文件.一般来说,我发现如果我已经运行`go install`,那么`go run`和`go build`之间的时间是可以容忍的.对于PowerShell上的Windows用户,该命令将是`go build -v {*}.go &&./ main.exe` (2认同)

Mat*_*att 46

我从 Node.js 转向 Go。相当于 Go 中的 Node.js__dirname是:

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

该线程中还提到了一些其他内容以及为什么它们是错误的:

  • 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
}
Run Code Online (Sandbox Code Playgroud)

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

更新 (12/23)正如 @VonC下面指出的,当您运行go build并分发二进制文件时,runtime.Caller(0), 将继续是您的目录。这可能不是您想要的。此行为与 不同__dirname,后者将反映文件所在位置的目录名。Go 中的这种行为没有完美的等价物。

  • 这应该是批准的答案。 (5认同)
  • 谢谢。这是我在挖掘多个答案和不同网站后找到的最佳答案。 (4认同)

vik*_*kyd 11

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)
}
Run Code Online (Sandbox Code Playgroud)

  • 在 Windows 上,这给了我一个 \Local\Temp 目录。 (3认同)

Von*_*onC 9

不要将“ Go语言推荐的答案”与 runtime.Caller(0).

go build当你或一个程序时,这会起作用go install,因为你正在重新编译它。

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

os.Args[0]或者,更好的是,os.Executable()此处提到)和(此处此处kardianos/osext提到)更可靠。

  • 同样,任何使用 getwd 的答案也将是错误的,特别是当 exe 被放置在路径中并从另一个位置执行时。 (2认同)

Aci*_*dic 8

filepath.Abs("./")
Run Code Online (Sandbox Code Playgroud)

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

如注释中所述,这将返回当前处于活动状态的目录.

  • 这将返回当前目录,而不是当前文件的目录.例如,如果从不同的路径调用可执行文件,则会有所不同. (5认同)

Ano*_*rog 5

如果您使用的软件包osext通过kardianos,你需要测试在当地,像德里克道林说:

这很好用,直到您想将它与 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)将是微不足道的,因为我只用几行代码就用其他编译器完成了......(著名的遗言;-)

  • 如果您希望它同时使用“go run”和构建的可执行文件,那么只需使用 `_, callerFile, _, _ := runtime.Caller(0)` `executablePath := filepath.Dir(callerFile)` 代替 (7认同)

ben*_*min 5

如果您使用这种方式:

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

使用诸如GoLang之类的IDE运行程序时,您将获得/ tmp路径,因为可执行文件将保存并从/ tmp运行

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

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

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

os.Getwd()函数将返回当前的工作目录。

  • 这是不正确的。这将返回执行进程的用户的工作目录,而不是文件的目录。使用文件路径.abs。 (2认同)

Isa*_*ten 5

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

package main

import (
    "fmt"
    "os"
)


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

    // or
    dir, _ := os.Getwd()
    fmt.Println(dir)
}
Run Code Online (Sandbox Code Playgroud)


gau*_*ora 5

dir, err := os.Getwd()
    if err != nil {
        fmt.Println(err)
    }
Run Code Online (Sandbox Code Playgroud)

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

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