80

io/ioutil用来读取一个小文本文件:

fileBytes, err := ioutil.ReadFile("/absolute/path/to/file.txt")

这很好用,但这并不是完全可移植的。就我而言,我要打开的文件在我的 GOPATH 中,例如:

/Users/matt/Dev/go/src/github.com/mholt/mypackage/data/file.txt

由于该data文件夹位于源代码旁边,因此我只想指定相对路径:

data/file.txt

但后来我得到这个错误:

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

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

请注意,我的问题是关于打开相对于 GOPATH 的文件。在 Go 中使用任何相对路径打开文件就像给出相对路径而不是绝对路径一样简单;文件是相对于编译后的二进制文件的工作目录打开的。在我的情况下,我想打开与二进制文件编译位置相关的文件。事后看来,这是一个糟糕的设计决定。)

4

5 回答 5

96

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

absPath, _ := filepath.Abs("../mypackage/data/file.txt")

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

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

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

于 2013-06-12T17:54:18.220 回答
47

这似乎工作得很好:

import "os"
import "io/ioutil"

pwd, _ := os.Getwd()
txt, _ := ioutil.ReadFile(pwd+"/path/to/file.txt")
于 2015-07-16T21:14:30.833 回答
12

我写了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))
}

您可以在我的GeoIP包中看到它使用的真实示例。Makefile生成代码,并使用geoip.goVFS。

于 2013-06-14T02:29:06.333 回答
4

我认为亚历克托马斯提供了答案,但根据我的经验,它并非万无一失。我将资源编译成二进制文件时遇到的一个问题是编译可能需要大量内存,具体取决于资产的大小。如果它们很小,那么可能没什么好担心的。在我的特定场景中,一个 1MB 的字体文件导致编译需要大约 1GB 的内存来编译。这是一个问题,因为我希望它可以在 Raspberry Pi 上获取。这是 Go 1.0;Go 1.1 中的情况可能有所改善。

所以在这种特殊情况下,我选择只使用go/build包来根据导入路径查找程序的源目录。当然,这需要您的目标进行GOPATH设置并且源可用。因此,它并非在所有情况下都是理想的解决方案。

于 2013-06-14T16:54:02.920 回答
0

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

给定文件结构:

-- main.go
-- data
  \- file.txt

您可以使用 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))
}

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

于 2022-03-01T18:09:07.917 回答