Go语言-打包静态文件
对于 Go 语言开发者来说,在享受语言便利性的同时,最终编译的单一可执行文件也是我们所热衷的。
但是,Go在编译成二进制文件时并没有把我们的静态资源文件编译进去,如果我们开发的是web应用的话就需要想办法把我们的静态文件也编译进去。
本文收集了一些Go语言中用来在编译过程中将静态文件打包到编译文件的方法。
<h1>go-bindata</h1>在 Go 语言的 Awesome 中你可以看到很多静态打包库,但是,你却看不到 go-bindata, go-bindata 明显更受欢迎,更流行。
go-bindata 很简单,设计理念也不难理解。它的任务就是讲静态文件封装在一个 Go 语言的 Source Code 里面,然后提供一个统一的接口,你通过这个接口传入文件路径,它将给你返回对应路径的文件数据。这也就是说它不在乎你的文件是字符型的文件还是字节型的,你自己处理,它只管包装。
简单来说就是它可以把我们的静态文件生成 .go 文件,这样就可以编译成二进制文件,项目启动的时候再把这个 .go 文件再释放成静态文件
<h2>下载</h2> <pre><code class="lang-shell hljs">go get -u github.com/jteeuwen/go-bindata/<span class="token punctuation">..</span>. </code></pre>安装确认
<pre><code class="lang-go hljs">C<span class="token punctuation">:</span>\Users\Administrator\Desktop<span class="token operator">></span><span class="token keyword">go</span><span class="token operator">-</span>bindata <span class="token operator">-</span>version <span class="token keyword">go</span><span class="token operator">-</span>bindata <span class="token number">3.1</span><span class="token number">.0</span> <span class="token punctuation">(</span>Go runtime go1<span class="token punctuation">.</span><span class="token number">14</span><span class="token punctuation">)</span><span class="token punctuation">.</span> Copyright <span class="token punctuation">(</span>c<span class="token punctuation">)</span> <span class="token number">2010</span><span class="token operator">-</span><span class="token number">2013</span><span class="token punctuation">,</span> Jim Teeuwen<span class="token punctuation">.</span> </code></pre>注意: GOPATH必须在环境变量下
<h2>使用</h2> <h3>例子一</h3> <pre><code class="lang-go hljs">ConfigTest ├── asset │ └── asset<span class="token punctuation">.</span><span class="token keyword">go</span> 静态文件编译之后的<span class="token keyword">go</span>文件 ├── cli # 运行目录 ├── config # 配置文件目录 │ ├── config<span class="token punctuation">.</span>json │ └── config<span class="token punctuation">.</span>yaml └── main # 程序目录 └── main<span class="token punctuation">.</span><span class="token keyword">go</span> # 源码 </code></pre>config.yaml内容
<pre><code class="lang-yaml hljs"><span class="token key atrule">enabled</span><span class="token punctuation">:</span> <span class="token boolean important">true</span> <span class="token key atrule">path</span><span class="token punctuation">:</span> aaaaa <span class="token key atrule">id</span><span class="token punctuation">:</span> <span class="token number">10</span> </code></pre>config.json内容
<pre><code class="lang-json hljs"><span class="token punctuation">{</span> <span class="token string">"enabled"</span><span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token string">"path"</span><span class="token punctuation">:</span> <span class="token string">"xxxx"</span><span class="token punctuation">,</span> <span class="token string">"id"</span><span class="token punctuation">:</span> <span class="token number">111</span> <span class="token punctuation">}</span> </code></pre>执行命令将静态文件打包成go文件
<pre><code class="lang-go hljs"><span class="token keyword">go</span><span class="token operator">-</span>bindata <span class="token operator">-</span>o<span class="token operator">=</span><span class="token punctuation">.</span><span class="token operator">/</span>asset<span class="token operator">/</span>asset<span class="token punctuation">.</span><span class="token keyword">go</span> <span class="token operator">-</span>pkg<span class="token operator">=</span>asset config<span class="token operator">/</span><span class="token operator">...</span> </code></pre>-o 输出文件到 ./asset/asset.go
包名 -pkg=asset
config/… # 指定需要打包的静态文件路径, …包括所有子目录
// 可以参考:https://www.cnblogs.com/landv/p/11577213.html
其路径变为:
<pre><code class="lang-go hljs">ConfigTest ├── asset │ └── asset<span class="token punctuation">.</span><span class="token keyword">go</span> 静态文件编译之后的<span class="token keyword">go</span>文件 ├── cli # 运行目录 ├── config # 配置文件目录 │ ├── config<span class="token punctuation">.</span>json │ └── config<span class="token punctuation">.</span>yaml └── main # 程序目录 └── main<span class="token punctuation">.</span><span class="token keyword">go</span> # 源码 </code></pre>main.go
<pre><code class="lang-go hljs"><span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">"configTest/asset"</span> <span class="token string">"encoding/json"</span> <span class="token string">"fmt"</span> <span class="token string">"gopkg.in/yaml.v2"</span> <span class="token string">"log"</span> <span class="token string">"os"</span> <span class="token string">"path/filepath"</span> <span class="token punctuation">)</span> <span class="token keyword">type</span> conf <span class="token keyword">struct</span> <span class="token punctuation">{</span> Enabled <span class="token builtin">bool</span> Path <span class="token builtin">string</span> ID <span class="token builtin">int</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token punctuation">(</span>c <span class="token operator">*</span>conf<span class="token punctuation">)</span> <span class="token function">ReadYaml</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> data<span class="token punctuation">,</span> <span class="token boolean">_</span> <span class="token operator">:=</span> asset<span class="token punctuation">.</span><span class="token function">Asset</span><span class="token punctuation">(</span><span class="token string">"config/config.yaml"</span><span class="token punctuation">)</span> err <span class="token operator">:=</span> yaml<span class="token punctuation">.</span><span class="token function">Unmarshal</span><span class="token punctuation">(</span>data<span class="token punctuation">,</span> <span class="token operator">&</span>c<span class="token punctuation">)</span> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> log<span class="token punctuation">.</span><span class="token function">Fatalf</span><span class="token punctuation">(</span><span class="token string">"Unmarshal: %v"</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token punctuation">(</span>c <span class="token operator">*</span>conf<span class="token punctuation">)</span> <span class="token function">ReadJson</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> data<span class="token punctuation">,</span> <span class="token boolean">_</span> <span class="token operator">:=</span> asset<span class="token punctuation">.</span><span class="token function">Asset</span><span class="token punctuation">(</span><span class="token string">"config/config.json"</span><span class="token punctuation">)</span> err <span class="token operator">:=</span> json<span class="token punctuation">.</span><span class="token function">Unmarshal</span><span class="token punctuation">(</span>data<span class="token punctuation">,</span> <span class="token operator">&</span>c<span class="token punctuation">)</span> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> log<span class="token punctuation">.</span><span class="token function">Fatalf</span><span class="token punctuation">(</span><span class="token string">"Unmarshal: %v"</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// 将dir解压到当前目录:根据生成的.go文件,将其解压为当前文件</span> <span class="token keyword">func</span> <span class="token function">restore</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 可以参考:https://www.cnblogs.com/landv/p/11577213.html</span> dirs <span class="token operator">:=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">string</span><span class="token punctuation">{</span><span class="token string">"config"</span><span class="token punctuation">}</span> <span class="token comment">// 设置需要释放的目录</span> isSuccess <span class="token operator">:=</span> <span class="token boolean">true</span> <span class="token keyword">for</span> <span class="token boolean">_</span><span class="token punctuation">,</span> dir <span class="token operator">:=</span> <span class="token keyword">range</span> dirs <span class="token punctuation">{</span> <span class="token comment">// 解压dir目录到当前目录</span> <span class="token keyword">if</span> err <span class="token operator">:=</span> asset<span class="token punctuation">.</span><span class="token function">RestoreAssets</span><span class="token punctuation">(</span><span class="token string">"./"</span><span class="token punctuation">,</span> dir<span class="token punctuation">)</span><span class="token punctuation">;</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> isSuccess <span class="token operator">=</span> <span class="token boolean">false</span> <span class="token keyword">break</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token operator">!</span>isSuccess <span class="token punctuation">{</span> <span class="token keyword">for</span> <span class="token boolean">_</span><span class="token punctuation">,</span> dir <span class="token operator">:=</span> <span class="token keyword">range</span> dirs <span class="token punctuation">{</span> os<span class="token punctuation">.</span><span class="token function">RemoveAll</span><span class="token punctuation">(</span>filepath<span class="token punctuation">.</span><span class="token function">Join</span><span class="token punctuation">(</span><span class="token string">"./"</span><span class="token punctuation">,</span> dir<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> c<span class="token punctuation">,</span> j conf j<span class="token punctuation">.</span><span class="token function">ReadJson</span><span class="token punctuation">(</span><span class="token punctuation">)</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"json:"</span><span class="token punctuation">,</span> j<span class="token punctuation">)</span> c<span class="token punctuation">.</span><span class="token function">ReadYaml</span><span class="token punctuation">(</span><span class="token punctuation">)</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"yaml:"</span><span class="token punctuation">,</span> c<span class="token punctuation">)</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"释放静态文件"</span><span class="token punctuation">)</span> <span class="token function">restore</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre> <ul><li>编译 main.go 执行二进制文件</li></ul><pre><code class="lang-shell hljs"><span class="token function">cd</span> cli <span class="token operator">&&</span> go build <span class="token punctuation">..</span>/main/main.go ./main </code></pre>json: {true xxxx 111}
yaml: {true aaaaa 10}
释放静态文件
执行之后会自动解压出config目录以及下面的静态文件
<pre><code class="lang-go hljs">ConfigTest ├── asset │ └── asset<span class="token punctuation">.</span><span class="token keyword">go</span> 静态文件编译之后的<span class="token keyword">go</span>文件 ├── cli # 运行目录 │ ├── config # 调用了<span class="token function">restore</span><span class="token punctuation">(</span><span class="token punctuation">)</span>会生成这个文件 │ │ ├── config<span class="token punctuation">.</span>json │ │ └── config<span class="token punctuation">.</span>yaml │ └── main # main<span class="token punctuation">.</span><span class="token keyword">go</span>编译之后生成的二进制执行文件 ├── config # 配置文件目录 │ ├── config<span class="token punctuation">.</span>json │ └── config<span class="token punctuation">.</span>yaml └── main # 程序目录 └── main<span class="token punctuation">.</span><span class="token keyword">go</span> # 源码 </code></pre>main.go
http.FileSystem是定义HTTP静态文件服务的接口。go-bindata的第三方包,go-bindata-assetfs实现了这个接口,支持http访问静态文件目录的行为。
访问 <code>http://localhost:12345</code>,就可以看到嵌入的静态资源目录的内容了
和 Nginx 查看静态文件目录一样的。
<code>go.rice</code> 也支持打包静态文件到 <code>go</code>文件中,但是行为和 <code>go-bindata</code>很不相同。从使用角度,<code>go.rice</code>其实是更便捷的静态文件操作库。打包静态文件反而是顺带的功能。
<h2>安装</h2> <pre><code class="lang-go hljs"><span class="token keyword">go</span> get github<span class="token punctuation">.</span>com<span class="token operator">/</span>GeertJohan<span class="token operator">/</span><span class="token keyword">go</span><span class="token punctuation">.</span>rice<span class="token operator">/</span><span class="token operator">...</span> </code></pre> <h2>使用一</h2> <pre><code class="lang-go hljs"><span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">"fmt"</span> <span class="token string">"html/template"</span> <span class="token string">"github.com/GeertJohan/go.rice"</span> <span class="token punctuation">)</span> <span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 这里写相对于的执行文件的地址</span> box<span class="token punctuation">,</span> err <span class="token operator">:=</span> rice<span class="token punctuation">.</span><span class="token function">FindBox</span><span class="token punctuation">(</span><span class="token string">"theme/default"</span><span class="token punctuation">)</span> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> <span class="token function">println</span><span class="token punctuation">(</span>err<span class="token punctuation">.</span><span class="token function">Error</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">}</span> <span class="token comment">// 从目录 Box 读取文件</span> str<span class="token punctuation">,</span> err <span class="token operator">:=</span> box<span class="token punctuation">.</span><span class="token function">String</span><span class="token punctuation">(</span><span class="token string">"post.html"</span><span class="token punctuation">)</span> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> <span class="token function">println</span><span class="token punctuation">(</span>err<span class="token punctuation">.</span><span class="token function">Error</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">}</span> t<span class="token punctuation">,</span> err <span class="token operator">:=</span> template<span class="token punctuation">.</span><span class="token function">New</span><span class="token punctuation">(</span><span class="token string">"tpl"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Parse</span><span class="token punctuation">(</span>str<span class="token punctuation">)</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>t<span class="token punctuation">,</span> err<span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre> <h2>使用二</h2>go.rice 是直接支持 http.FileSystem 接口:
<pre><code class="lang-go hljs"><span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">"github.com/GeertJohan/go.rice"</span> <span class="token string">"net/http"</span> <span class="token punctuation">)</span> <span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> http<span class="token punctuation">.</span><span class="token function">Handle</span><span class="token punctuation">(</span><span class="token string">"/"</span><span class="token punctuation">,</span> http<span class="token punctuation">.</span><span class="token function">FileServer</span><span class="token punctuation">(</span>rice<span class="token punctuation">.</span><span class="token function">MustFindBox</span><span class="token punctuation">(</span><span class="token string">"../config"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">HTTPBox</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> http<span class="token punctuation">.</span><span class="token function">ListenAndServe</span><span class="token punctuation">(</span><span class="token string">":12345"</span><span class="token punctuation">,</span> <span class="token boolean">nil</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre>有点略繁琐的是 rice.FindBox(dir) 只能加载一个目录。因此需要多个目录的场景,会有代码:
<pre><code class="lang-go hljs"><span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> http<span class="token punctuation">.</span><span class="token function">Handle</span><span class="token punctuation">(</span><span class="token string">"/img"</span><span class="token punctuation">,</span> http<span class="token punctuation">.</span><span class="token function">FileServer</span><span class="token punctuation">(</span>rice<span class="token punctuation">.</span><span class="token function">MustFindBox</span><span class="token punctuation">(</span><span class="token string">"static/img"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">HTTPBox</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> http<span class="token punctuation">.</span><span class="token function">Handle</span><span class="token punctuation">(</span><span class="token string">"/css"</span><span class="token punctuation">,</span> http<span class="token punctuation">.</span><span class="token function">FileServer</span><span class="token punctuation">(</span>rice<span class="token punctuation">.</span><span class="token function">MustFindBox</span><span class="token punctuation">(</span><span class="token string">"static/css"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">HTTPBox</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> http<span class="token punctuation">.</span><span class="token function">Handle</span><span class="token punctuation">(</span><span class="token string">"/js"</span><span class="token punctuation">,</span> http<span class="token punctuation">.</span><span class="token function">FileServer</span><span class="token punctuation">(</span>rice<span class="token punctuation">.</span><span class="token function">MustFindBox</span><span class="token punctuation">(</span><span class="token string">"static/js"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">HTTPBox</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> http<span class="token punctuation">.</span><span class="token function">ListenAndServe</span><span class="token punctuation">(</span><span class="token string">":12345"</span><span class="token punctuation">,</span> <span class="token boolean">nil</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre> <h1>esc</h1>esc 的作者在研究几款嵌入静态资源的 工具 后,发觉都不好用,就自己写出了 esc。它的需求很简单,就是嵌入静态资源 和 支持 http.FileSystem 。esc 工具也这两个主要功能。
<h2>安装</h2>go get github.com/mjibson/esc
<h2>使用</h2>使用方法和 go-bindata 类似:
<pre><code class="lang-shell hljs">// 注意 esc 不支持 source/<span class="token punctuation">..</span>. 三个点表示所有子目录 go-bindata -o<span class="token operator">=</span>asset/asset.go -pkg<span class="token operator">=</span>asset <span class="token function">source</span> theme doc/source doc/theme </code></pre> <pre><code class="lang-go hljs"><span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">"net/http"</span> <span class="token string">"asset"</span> <span class="token comment">// esc 生成 asset/asset.go </span> <span class="token punctuation">)</span> <span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span>asset<span class="token punctuation">.</span><span class="token function">FSString</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token string">"/theme/default/post.html"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// 读取单个文件</span> http<span class="token punctuation">.</span><span class="token function">ListenAndServe</span><span class="token punctuation">(</span><span class="token string">":12345"</span><span class="token punctuation">,</span> http<span class="token punctuation">.</span><span class="token function">FileServer</span><span class="token punctuation">(</span>asset<span class="token punctuation">.</span><span class="token function">FS</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// 支持 http.FileSystem,但是没有做展示目录的支持</span> <span class="token punctuation">}</span> </code></pre>esc 有个较大的问题是只能一个一个文件操作,不能文件夹操作,没有类似 go-bindata 的 asset.RestoreDir() 方法。并且没有方法可以列出嵌入的文件的列表,导致也无法一个一个文件操作,除非自己写死。这是我不使用他的最大原因。
<h1>go generate</h1>嵌入静态资源的工具推荐配合 go generate 使用
参考:https://www.cnblogs.com/landv/p/11577213.html
到此这篇关于“Go语言-打包静态文件”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!您可能感兴趣的文章:
想系统学习GO语言(Golang
从零开始学习GO语言-搭建Go语言开发环境-快速开发入门第一个小程序
go语言http服务处理image/css/js等静态文件
Go语言发展历史、核心、特性及学习路线
初识 Go 语言
查看go 安装了哪些包_go语言基础入门(一)
golang静态代码检查_Golang面试题41道
Go 语言学习第一章节
Hyperledger Fabric2.2环境搭建(一)——go语言
golang 文件md5_Golang面试题41道