如何在Go中使用相对路径打开文件?

Mat*_*att 64 go filepath

我正在io/ioutil阅读一个小文本文件:

fileBytes, err := ioutil.ReadFile("/absolute/path/to/file.txt")
Run Code Online (Sandbox Code Playgroud)

这样做很好,但这不是完全可移植的.在我的例子中,我要打开的文件在我的GOPATH中,例如:

/Users/matt/Dev/go/src/github.com/mholt/mypackage/data/file.txt
Run Code Online (Sandbox Code Playgroud)

由于data文件夹与源代码一起使用,我只想指定相对路径:

data/file.txt
Run Code Online (Sandbox Code Playgroud)

但后来我得到了这个错误:

恐慌:打开data/file.txt:没有这样的文件或目录

如何使用相对路径打开文件,特别是如果它们与我的Go代码一起使用?

Mat*_*att 74

嗯...... path/filepath包装有Abs()哪些我需要的东西(到目前为止)虽然有点不方便:

absPath, _ := filepath.Abs("../mypackage/data/file.txt")
Run Code Online (Sandbox Code Playgroud)

然后我absPath用来加载文件,它工作正常.

请注意,在我的情况下,数据文件位于与main我运行程序的包不同的包中.如果它都在同一个包中,我会删除前导../mypackage/.由于该路径显然是相对的,因此不同的程序将具有不同的结构并且需要相应地调整.

如果有更好的方法将外部资源与Go程序一起使用并保持其可移植性,请随时提供另一个答案.

  • 你学到了什么?:)我们不应该跨包共享这样的文件吗? (11认同)
  • @Matt,分享爱情.如果你有更好的东西,不要使用这个"小技巧".你是谷歌的最佳结果. (6认同)
  • 这个问题来自我在Go的第一周编程.更好的问题是如何将所需数据与程序捆绑在一起.我的回答是针对我非常具体的情况,我希望人们不会随意使用这种情况. (2认同)

spe*_*oly 31

这似乎工作得很好:

import "os"
import "io/ioutil"

pwd, _ := os.Getwd()
txt, _ := ioutil.ReadFile(pwd+"/path/to/file.txt")
Run Code Online (Sandbox Code Playgroud)

  • 这是糟糕的形式,因为/是特定于操作系统,在连接路径时最好使用filepath.join(),因为它将使用os.PathSeperator (10认同)
  • 让我为那些愿意遵循先前评论中的(好的)建议的人节省时间:使用`import“ path / filepath”`并调用`filepath.Join(...)`(大写字母J)。:-) (5认同)
  • `os.Open(pwd + "../mocks/product/default.json")` 你如何处理这种情况?它把这个当作字面意思。 (2认同)

Ale*_*mas 9

我写了gobundle来解决这个问题.它从数据文件生成Go源代码,然后将其编译到二进制文件中.然后,您可以通过类似VFS的图层访问文件数据.它完全可移植,支持添加整个文件树,压缩等.

缺点是您需要一个中间步骤来从源数据构建Go文件.我通常使用make来做这件事.

这是你如何迭代一个包中的所有文件,读取字节:

for _, name := range bundle.Files() {
    r, _ := bundle.Open(name)
    b, _ := ioutil.ReadAll(r)
    fmt.Printf("file %s has length %d\n", name, len(b))
}
Run Code Online (Sandbox Code Playgroud)

您可以在我的GeoIP包中看到它的一个真实示例.的Makefile生成的代码,并geoip.go使用该VFS.


Dan*_*van 8

从Go 1.16开始,你可以使用embed包。这允许您将文件嵌入到正在运行的 go 程序中。

给定文件结构:

-- main.go
-- data
  \- file.txt
Run Code Online (Sandbox Code Playgroud)

您可以使用 go 指令引用该文件

package main

import (
  "embed"
  "fmt"
)

//go:embed data/file.txt
var content embed.FS

func main() {
  text, _ := content.ReadFile("data/file.txt")
  fmt.Println(string(text))
}
Run Code Online (Sandbox Code Playgroud)

无论程序在哪里执行,该程序都会成功运行。如果可以从多个不同位置(例如,从测试目录)调用该文件,这非常有用。