我正在使用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
但后来我收到了这个错误:
恐慌:打开data / file.txt:没有这样的文件或目录
如何使用相对路径打开文件,特别是如果它们与我的Go代码一起使用?
(请注意,我的问题是关于打开相对于GOPATH的文件。使用Go中的任何相对路径打开文件就像给出相对路径而不是绝对路径一样简单;文件是相对于编译的二进制文件的工作目录打开的。在我的例子中,我想打开相对于编译二进制文件的文件。事后看来,这是一个糟糕的设计决定。)
答案 0 :(得分:70)
嗯... path/filepath
包有Abs()
,它可以满足我的需要(到目前为止),虽然它有点不方便:
absPath, _ := filepath.Abs("../mypackage/data/file.txt")
然后我使用absPath
加载文件,它运行正常。
请注意,在我的情况下,数据文件位于与我正在运行程序的main
包分开的包中。如果它全部在同一个包中,我将删除前导../mypackage/
。由于这条路径显然是相对的,不同的程序将有不同的结构,需要相应调整。
如果有更好的方法将外部资源与Go程序一起使用并保持便携,请随时提供其他答案。
答案 1 :(得分:27)
这看起来效果很好:
import "os"
import "io/ioutil"
pwd, _ := os.Getwd()
txt, _ := ioutil.ReadFile(pwd+"/path/to/file.txt")
答案 2 :(得分:8)
我写了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))
}
答案 3 :(得分:2)
我认为Alec Thomas提供了The Answer,但根据我的经验,它并非万无一失。我在将资源编译到二进制文件时遇到的一个问题是编译可能需要大量内存,具体取决于资产的大小。如果它们很小,那么可能无需担心。在我的特定场景中,一个1MB的字体文件导致编译需要大约1GB的内存来编译。这是一个问题,因为我希望它可以在Raspberry Pi上获得。这是Go 1.0; Go 1.1中的情况可能有所改善。
因此,在特定情况下,我选择使用go/build
包根据导入路径查找程序的source directory。当然,这需要您的目标设置GOPATH
并且源可用。所以在所有情况下都不是理想的解决方案。