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.go
pwd 是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