如何在操作系统时查找同级文件.Getwd() 在不同的环境中是不同的


myprogram/
|
|-main.go
|-dir1/
|-data/
|-datafile.json
|-runner.go
|-runner_test.go

runner.go中,我有一个简单的函数来读取datafile.json。类似的东西

func GetPayload() (string, err) {
dBytes, dErr := ioutil.ReadFile("dir1/data/datafile.json")
if dErr != nil { return nil, dErr}
return dBytes, nil
}

我在结构类似于上述结构的 Lambda 中使用 Go。当 Lambda 在其实际环境中运行时,它会从main.go开始,然后从runner.go调用GetPayload()。但是,我在runner_test.go的一台简单工作节点机器上进行了测试,该测试也达到了GetPayload()

在"正常"执行期间(从main.go) - 这工作正常。但是,当从runner_test.go调用GetPayload()时,它会出错,说

打开 dir1/data/datafile.json 没有这样的文件或目录

这是有道理的,因为在测试期间,工作目录是容纳runner_test.go的目录,这是data/的,所以没有dir1作为它的子目录。我一直在尝试使用os.Getwd()并从那里获取路径,例如:

pwd, _ := os.Getwd()
dBytes, dErr := ioutil.ReadFile(pwd + "dir1/data/datafile.json")

但同样,这是行不通的,因为对于runner_test.gopwd 是user/myname/myprogram/dir1,但从main.go,它显示为user/myname/myprogram.

知道如何在任何环境中从内部GetPayload()查找和打开datafile.json吗?我可以将可选参数传递给GetPayload()但如果可能的话,避免这种情况会很棒。

如果文件是静态的(意味着在生成程序后不需要更改),则可以将其嵌入到生成的程序中。这意味着您不再需要担心运行时文件路径。

import (
"embed"
)
//go:embed data/*
var dataFiles embed.FS
func GetPayload() (string, err) {
dBytes, dErr := dataFiles.ReadFile(dataFiles, "data/datafile.json")
if dErr != nil { return nil, dErr}
return dBytes, nil
}

现在,data/目录中的文件嵌入在此变量dataFiles中,该变量充当只读文件系统。

欲了解更多信息:

在包文档概述中阅读有关嵌入的详细信息。

阅读我关于"何时使用嵌入"的答案

对于程序在运行时需要的数据文件,请使用固定目录并引用该目录,或者接受命令行参数或某种配置来告诉您文件的位置。

运行单元测试时,wd 是包含测试文件的目录。一种约定是在包含测试的目录下使用 testdata/目录,并将所有数据文件放在那里。这样,您就可以使用testdata/datafile.json从测试中引用该文件。

您可以使用运行时所需文件的副本作为测试文件,也可以使用从运行时数据文件到 testdata/dir 下的测试文件的符号链接。

对于程序在运行时需要的数据文件,请使用固定的 目录并参考

有人提出了这个建议,我同意。为此,您可以使用 像这样:

package main
import (
"os"
"path/filepath"
)
func main() {
d, err := os.UserCacheDir()
if err != nil {
panic(err)
}
d = filepath.Join(d, "file.json")
f, err := os.Open(d)
if err != nil {
panic(err)
}
defer f.Close()
os.Stdout.ReadFrom(f)
}
  • https://golang.org/pkg/os#UserCacheDir
  • https://golang.org/pkg/os#UserConfigDir

最新更新