加载所需文件,相对于绝对路径

时间:2017-08-08 23:08:52

标签: file go path

我们有一个程序,人们可以在他们的机器上编译。它有一个HTTP接口,但也可以通过命令行调用。

为了为HTTP客户端提供一些漂亮的错误页面,我们希望提供错误页面。我们正在使用一个非常简单的解决方案,使用go html/template包。

因此,为了让程序找到模板,我们目前正在做:

func init() {
  prefStr := "path/to/http/tmpl"
  pathPrefix,err := filepath.Abs(prefStr)
  if err != nil {
    log.Warn("Template path %s is not available!", prefStr)
  }

  pathPrefix + "/err.html"
}

现在在调试应用程序时,这通常很有效 - 我们位于程序包的根目录中,因此filepath.Abs()正确解析,如下所示: $GOPATH/github.com/user/repo/path/to/http/tmpl(正确展开$GOPATH

但是当我们从命令行通过可执行文件调用应用程序时,这不起作用。当然可以从文件系统的任何地方调用命令行,以方便例如在当前目录中提供一个文件作为参数。

简而言之,由于目录的错误连接,运行/some/other/path/on/fs/our-executable filename.txt会导致上面的init()函数崩溃:创建绝对路径需要/some/other/path/on/fs/,这是错误的。因此它崩溃了 panic: open /some/other/path/on/fs/path/to/http/tmpl/err.html: no such file or directory

我已经搜索过,到目前为止只发现了这个: How can I open files using relative paths in Go?

但这并不适用于我们。 另一个解决方案建议捆绑已编译的go资源,但这似乎很奇怪,因为错误页面是html文本。

我们也尝试过 https://stackoverflow.com/a/31464648/169252

但它有同样的效果。

我们如何确保路径始终正确解析?这似乎不是一件难以完成的事情,但到目前为止我们还没有管理过。

编辑:这不是问题How can I open files using relative paths in Go?的完全重复。正如我在问题文本中已经提到的那样,我自己已经查过了。它建议使用filepath.Abs()。但正如我的问题所述,对我们来说,这不起作用,好像我们的可执行文件是从不同的地方调用的,filepath.Abs()没有返回相同的值,因此不会为我们工作。

3 个答案:

答案 0 :(得分:0)

我认为你的挑战是人们可以在磁盘上的任何地方安装程序,程序必须足够聪明才能知道以后的位置。

我看到的一种常见方法是人们通常使用environment variables将它们锚定到应用程序的安装路径。我相信您可能已经看到了*_HOME命名模式的环境变量,如JAVA_HOMEMAVEN_HOME,它们的值始终是安装位置的文件路径。

我想你可以在这里做同样的事情。强制您的用户定义MYAPP_HOME变量,并在应用程序开始时确保它已设置,否则会抛出错误,指出MYAPP_HOME未设置。

然后,您需要做的只是简单查找MYAPP_HOME + /http/tmpl的值,以获取模板html文件。

示例:

package main

import "os"

func main() {
    // Assuming MYAPP_HOME has been verified that it is set
    // Then:
    tmlPath := os.Getenv("MYAPP_HOME") + "/http/tmpl/"
    errTml := tmlPath + "err.html"
}

答案 1 :(得分:0)

如果您不热衷于使用当前工作目录或传入目录,则可以通过从os包调用os.Executable来找到绝对可执行路径。

appPath, err := os.Executable()

os包通常包含os特定的东西,比如如何获取当前的工作目录。如果你曾经卡住了,那么值得一看plang文档和golang.org上的软件包列表,因为它们非常好,通常你会在那里找到答案。

https://golang.org/pkg/os

如果用户使用go get安装,你可以采取的另一种方法是依赖于你的模板将在GOPATH下使用pkg安装的事实,所以你总能在$ GOPATH / src / your / project / path找到它们/ templates(或〜/默认gopath,因为它不是严格要求的)。

最安全的方法可能是将它们与虚拟文件系统中的二进制文件捆绑在一起,因为这意味着您不依赖任何外部操作,也不关心托管应用程序的位置,甚至根本无法访问文件。

答案 2 :(得分:0)

我建议在这种情况下使用相对路径。

根据您的描述,您似乎正在开发Web应用程序。虽然它在单个开发人员的计算机上运行良好,但您需要注意您的应用程序可以部署在生产服务器上的任何目录下。您无法确定应用程序的部署位置,但您始终可以确定静态文件相对于应用程序根目录的位置。

在命令行中调用应用程序时,应将所有必需的静态文件复制到与开发环境完全相同的相同相对路径。我的典型结构是:

project/
    |- config.json
    |- main.go
    |- package1/
    |- package2/
    |- static/
       |- templates/
       |  |- index.html
       |  |- base.html
       |- css/
       |- javascript/
       |- image/

当您准备从命令行运行应用程序时,请确保将config.json和static /目录复制到与可执行二进制文件相同的级别。然后,您需要做的就是在代码中使用相对路径而不做任何噩梦。