```go
package main
import (
"compress/zlib"
"fmt"
"io"
"log"
"os"
"path/filepath"
)
func main() {
type fileInfo struct {
file string
size int64
}
fileList := make(map[string]fileInfo, len(os.Args))
for _, v := range os.Args[1:] {
if f, err := os.Stat(v); err == nil || os.IsExist(err) {
fileList[filepath.Base(v)] = fileInfo{file: v, size: f.Size()}
}
}
if len(fileList) == 0 {
log.Fatal(os.Args, "input error")
}
fw, err := os.Create("resources.go")
if err != nil {
log.Fatal(err)
}
defer fw.Close()
fw.WriteString(`package main
import (
"compress/zlib"
"errors"
"io"
"os"
)
func WriteBytesToFile(path, name string) error {
ok, err := checkFileIsOk(path, name)
if err != nil || ok {
return err
}
zr, err := zlib.NewReader(NewStringReader(getBytesFromMap(name)))
if err != nil {
return err
}
fw, err := os.Create(path)
if err != nil {
return err
}
defer fw.Close()
if _, err = io.Copy(fw, zr); err != nil {
return err
}
return zr.Close()
}
func checkFileIsOk(path, name string) (bool, error) {
size, ok := map[string]int64{
`)
for k, v := range fileList {
fmt.Fprintf(fw, " \"%s\": %d,\n", k, v.size)
}
fw.WriteString(` }[name]
if !ok {
return false, errors.New("name not find")
}
f, err := os.Stat(path)
return (err == nil || os.IsExist(err)) && size == f.Size(), nil
}
func getBytesFromMap(name string) ([]byte, int) {
data := map[string]struct {
s string
l int
}{
`)
for k, v := range fileList {
fmt.Fprintf(fw, " \"%s\": {s: \"", k)
l, err := writeDataToFile(fw, v.file)
if err != nil {
log.Fatal(err)
}
fmt.Fprintf(fw, "\",\n l: %d},\n", l)
}
fw.WriteString(` }[name]
return []byte(data.s), data.l
}
type StringReader struct {
buf []byte
off, l int
}
func NewStringReader(p []byte, l int) io.Reader {
for i := 0; i < l; i++ {
p[i] = (p[2*i]-'a')<<4 | (p[2*i+1] - 'a')
}
return &StringReader{buf: p[:l:l], off: 0, l: l}
}
func (sr *StringReader) Read(p []byte) (int, error) {
if sr.off >= sr.l {
if len(p) == 0 {
return 0, nil
}
return 0, io.EOF
}
n := copy(p, sr.buf[sr.off:])
sr.off += n
return n, nil
}`)
}
func writeDataToFile(fw *os.File, file string) (int, error) {
fr, err := os.Open(file)
if err != nil {
return 0, err
}
defer fr.Close()
sw := &StringWriter{w: fw, wLen: 0}
zw := zlib.NewWriter(sw)
if _, err = io.Copy(zw, fr); err != nil {
return 0, err
}
if err = zw.Close(); err != nil {
return 0, err
}
return sw.wLen, nil
}
type StringWriter struct {
wLen int
w io.Writer
}
const lowerHex = "abcdefghijklmnop"
func (sw *StringWriter) Write(p []byte) (n int, err error) {
if len(p) > 0 {
var (
b byte
buf = make([]byte, 2)
)
for n, b = range p {
buf[0], buf[1] = lowerHex[b>>4], lowerHex[b&0xf]
if _, err = sw.w.Write(buf); err != nil {
return
}
}
n++
sw.wLen += n
}
return
}
```
使用方法很简单:
add_file_to_go.exe a.txt b.jpg c.exe
此时会产生一个resources.go文件,加入到你的项目中。
在程序运行开始的时候调用:
WriteBytesToFile("c:\\a.txt", "a.txt")
WriteBytesToFile("c:\\b.jpg", "b.jpg")
WriteBytesToFile("c:\\c.exe", "c.exe")
既可以将文件写入到指定目录,如果文件已经存在则不会重复写入。最早想的是使用md5值判断文件是否改变,但想想有点耗性能,
而且大部分时间这些文件是不会改变的,因此改成判断文件大小,及如果有人改写了这些文件,下次运行时会重新将正确的文件写入。
我使用了zlib的压缩方法将文件压缩了一次,保证生成的resources.go很小。灵感来源于这个开源项目
[点击跳转](https://github.com/jteeuwen/go-bindata)
但是实现完全是我自己写的,思想和那个开源项目类似。
有疑问加站长微信联系(非本文作者))