如何从代码和测试中引用相对文件

19
我需要从 patients.go 引用 patients.json 文件,文件夹结构如下:

enter image description here

如果我执行以下操作:

filepath.Abs("../../conf/patients.json")

对于 go test ./... 来说是可以工作的,但对于 revel run 就会失败。
如果我执行以下操作:

filepath.Abs("conf/patients.json")

则情况恰好相反(revel 可以工作但测试失败)。
有没有一种正确引用该文件的方法,使其在测试和正常程序运行时都能正常工作?
3个回答

11

相对路径始终基于某个基本路径进行解释/解析:当前或工作目录 - 因此它总会有其限制。

如果您可以始终注意正确的工作目录,那么可以继续使用相对路径。

我建议的是不要依赖于工作目录,而是显式指定一个基本路径。这可以在应用程序中硬编码默认值(可能也是工作目录),并应提供多种方法来覆盖其值。

覆盖“相对”路径所解析到的基本路径的推荐方法:

  1. 命令行标志(请参见flag包)
  2. 环境变量(请参见os.Getenv()
  3. (修复名称的)用户主目录中的配置文件(请参见os/user/Useros/user/Current()

一旦您有了基本路径,就可以通过连接基本路径和相对路径来获取完整路径。您可以使用path.Join()filepath.Join(),例如:

// Get base path, from any or from the combination of the above mentioned solutions
base := "/var/myapp"

// Relative path, resource to read/write from:
relf := "conf/patients.json"

// Full path that identifies the resource:
full := filepath.Join(base, relf) // full will be "/var/myapp/conf/patients.json"

有没有一种方法可以知道.go文件的路径? - Pablo Fernandez
2
@PabloFernandez 如果编译成可执行二进制文件,甚至就没有 .go 文件了... - icza
在Linux上,如果已经挂载了/proc,那么可以通过调用os.Readlink()函数来获取正在执行的程序的位置,该函数针对名为"/proc/self/exe"的符号链接。无论哪种情况,这都不是可移植的;而且,在GNU/Linux系统上,一个正确打包的软件包应该将其二进制文件和“资产”分开,因此这种方法可能没有太多意义。 - kostix
2
我还想提出另一种可能性:1)定义一个全局变量,用于指定资源的基本目录前缀,例如 main.AssetsDir;2)允许下游打包者在构建时使用链接器覆盖字符串类型值,例如:go build -ldflags="-X main.AssetsDir=/usr/share/cool_app/assets"。OP可以通过研究go help buildgo tool link -h的输出来了解更多背景信息。 - kostix
@kostix 不错的想法,但这会限制开发人员的可配置性。没有编程知识的用户会发现命令行标志比构建标志更友好和易于使用。 - icza

2

不确定为什么,但是BasePathAppPath都返回空字符串:/ - Pablo Fernandez
@PabloFernandez 你调用了 revel.Init() 吗? - alediaferia
链接已失效。新的链接似乎是https://revel.github.io/。 - Matt3o12

0

这不是路径的问题,而是你设计的问题。

你应该更加仔细地设计你的代码。

据我所知,你在测试文件和 reveal run 中共享相同的路径。我猜想你可能在模型包中硬编码了你的 json 路径,这是不建议的。

更好的方法是:

  • 模型包从全局配置获取 json 路径,或者使用类似 model := NewModel(config_path) 的方式初始化模型。这样 reveal run 就可以使用任何你想要的 json 来初始化模型。
  • 在你的 xxxx_testing.go 文件中硬编码 "../../conf/patients.json"。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接