英文:
How to embed file for later parsing execution use
问题
我本质上是在尝试遍历一个包含HTML文件的文件夹。我想将它们嵌入到二进制文件中,并能够在请求时解析它们以进行模板执行。如果我没有表达清楚,请原谅我。
任何想法、技巧或更好的方法都非常感谢。
// 模板文件
type TempFiles struct {
Files map[string]string
}
// 遍历视图文件并加载它们
func LoadTempFiles() {
t := new(TempFiles)
// 加载模板文件
filepath.Walk("application/views", func(path string, info os.FileInfo, err error) error {
if !info.IsDir() {
content, _ := ioutil.ReadFile(path)
t.Files[path] = string(content)
}
return nil
})
}
func ViewTemp(w http.ResponseWriter, path string) {
t := new(TempFiles)
temp, err := template.New().Parse(t.Files[path])
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
} else {
temp.Execute(w, nil)
}
}
英文:
I am essentially trying to walk through a folder of html files. I want to embed them into the binary file and be able to parse them upon request for template execution purposes. (Please excuse me if im not wording this properly).
Any ideas, tips, tricks or better way of accomplishing this is much appreciated.
<!-- language: lang-go -->
// Template Files
type TempFiles struct {
Files map[string]string
}
// Loop through view files and load them
func LoadTempFiles() {
t := new(TempFiles)
// Load template files
filepath.Walk("application/views", func(path string, info os.FileInfo, err error) error {
if !info.IsDir() {
content, _ := ioutil.ReadFile(path)
t.Files[path] = string(content)
}
return nil
})
}
func ViewTemp(w http.ResponseWriter, path string) {
t := new(TempFiles)
temp, err := template.New().Parse(t.Files[path])
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
} else {
temp.Execute(w, nil)
}
}
答案1
得分: 48
我在大多数Go web应用程序中都这样做。我使用go-bindata从我想要嵌入的所有文件中自动生成Go源代码,然后将它们编译到二进制文件中。
所有这些都是在构建过程中自动完成的。
一个缺点是当前的go构建工具没有提供一种方式来钩入构建过程,所以我使用一个Makefile来实现这个目的。当调用makefile时,它运行go-bindata
来为所有必要的文件生成源代码,然后通常执行一些额外的代码生成工作(特别是创建一个列出所有嵌入文件的Go源文件..就像一个目录表)。然后继续编译实际的程序。
这可能会变得有点混乱,但你只需要设置一次。
另一个缺点是,使用Makefile意味着该软件与go get
命令不兼容。但由于我的大多数web应用程序都不打算共享,所以到目前为止这还不是一个问题。
当涉及到调试/开发这样的应用程序时,嵌入静态web内容会出现另一个问题:我不能只编辑一个HTML或CSS文件并刷新浏览器以查看其效果。我必须停止服务器,重新构建并重新启动它以进行每次编辑。这显然不是理想的,所以我将Makefile分成了debug
和release
模式。发布模式执行我上面描述的操作。然而,调试模式不会实际嵌入静态文件。它会为每个文件生成源文件,但是这些源文件不包含实际的文件数据,而是包含一个简单从文件系统加载数据的存根。
就服务器代码而言,生成的代码没有任何区别。它只是调用一个函数来获取给定静态文件的内容。它不关心该内容是实际嵌入在二进制文件中,还是从外部源加载的。因此,这两种构建模式可以自由互换。
例如,在发布模式和调试模式下,用于获取静态文件内容的相同生成函数如下所示:
发布模式:
func index_html() []byte {
return []byte {
....
}
}
调试模式:
func index_html() []byte {
data, err := ioutil.ReadFile("index.html")
...
return data
}
两种情况下的接口是相同的。这样可以轻松无忧地进行开发和调试。
英文:
I do this with most of my Go web apps. I use go-bindata to auto-generate Go source code from all the files I want to embed and then compile them into the binary.
All this is done automatically during build.
One downside is that the current go build tools do not offer a way to hook into the build process, so I use a Makefile for this purpose. When the makefile is invoked, it runs go-bindata
to generate the sources for all necessary files, then usually performs some additional code generation bits and bobs (notably, creating a Go source file which lists all the embedded files in a map.. A Table of Contents if you will). It then proceeds to compile the actual program.
This can become a little messy, but you only have to set it all up once.
Another downside, is that the use of a Makefile means the software is not compatible with the go get
command. But since most of my web apps are not meant to be shared anyway, this has not been a problem so far.
When it comes to debugging/developing such an application, there is another issue that arises from embedding the static web content: I can't just edit an HTML or CSS file and refresh the browser to see its effects. I would have to stop the server, rebuild it and restart it with every edit. This is obviously not ideal, so I split the Makefile up into a debug
and release
mode. The release mode does what I described above. The debug mode, however, wil not actually embed the static files. It does generate source files for each of them, but instead of having them contain the actual file data, it contains a stub which simply loads the data from the filesystem.
As far as the server code is concerned, there is no difference in the generated code. All it does is call a function to fetch the contents of a given static file. It does not care whether that content is actually embedded in the binary, or if it's loaded from an external source. So the two build modes are freely interchangeable.
For example, the same generated function to fetch static file content in release and debug mode would look as follows:
Release mode:
func index_html() []byte {
return []byte {
....
}
}
Debug mode:
func index_html() []byte {
data, err := ioutil.ReadFile("index.html")
...
return data
}
The interface in both cases is identical. This allows for easy and care-free development and debugging.
答案2
得分: 18
另一个要考虑的工具:另一个最近的好工具来自esc: 在Go中嵌入静态资源(GitHub仓库)
> 一个程序可以:
> - 可以接受一些目录,并递归地将其中的所有文件嵌入,以与http.FileSystem兼容的方式
- 可以选择在本地开发时禁用,以便与本地文件系统一起使用
- 不会在后续运行中更改输出文件
- 当文件更改时,差异大小合理
- 友好于供应商
> 友好于供应商意味着当我运行godep
或party时,静态嵌入文件不会更改。
这意味着它不能有任何第三方导入(因为它们的导入路径将在goimports
期间被重写,因此与工具本身生成的不同),或者需要第三方导入的可指定位置。
> 它生成漂亮的gzip字符串,每个文件一个。
有一个简单的标志来启用本地开发模式,它足够聪明,不会从文件名中删除目录前缀(这是esc
中的一个选项,有时是必需的)。
输出包括所有所需的代码,并且不依赖于任何第三方库与http.FileSystem
兼容。
英文:
Another tool to consider: Another recent good tool comes from esc: Embedding Static Assets in Go (GitHub repo)
> a program that:
> - can take some directories and recursively embed all files in them in a way that was compatible with http.FileSystem
- can optionally be disabled for use with the local file system for local development
- will not change the output file on subsequent runs
- has reasonable-sized diffs when files changed
- is vendoring-friendly
> Vendoring-friendly means that when I run godep
or party, the static embed file will not change.
This means it must not have any third-party imports (since their import path will be rewritten during goimports
, and thus different than what the tool itself produces), or a specifiable location for the needed third-party imports.
> It generates nice, gzipped strings, one per file.
There is a simple flag to enable local development mode, which is smart enough to not strip directory prefixes off of filenames (an option in esc
that is sometimes needed).
The output includes all needed code, and does not depend on any third-party libraries for compatibility with http.FileSystem
.
答案3
得分: 8
我制作了一个包,使得在调试和生产环境之间切换更加容易。它还提供了一个http.FileSystem实现,使得服务器文件变得简单。并且它有几种将文件添加到二进制文件中的方式(生成go代码或追加为zip文件)。
https://github.com/GeertJohan/go.rice
英文:
I made a package that makes switching between debug and production easier. It also provides an http.FileSystem implementation, making it easy to server the files. And it has several ways of adding the files to the binary (generate go code, or append as zip).
https://github.com/GeertJohan/go.rice
答案4
得分: 1
Go现在内置了对此的支持:
package main
import (
"embed"
"os"
)
//go:embed *.html
var content embed.FS
func main() {
b, e := content.ReadFile("index.html")
if e != nil {
panic(e)
}
os.Stdout.Write(b)
}
英文:
Go now has builtin support for this:
package main
import (
"embed"
"os"
)
//go:embed *.html
var content embed.FS
func main() {
b, e := content.ReadFile("index.html")
if e != nil {
panic(e)
}
os.Stdout.Write(b)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论