最近闲的没事干在捣鼓 fyne,想用Golang去写桌面程序(图一乐),因为要解决 fyne的中文乱码问题,需要将字体文件打包时内嵌到程序中,捣鼓了半天没搞定,突然发现了Golang的新特性,就用了一下,还挺有意思的,所以就顺便记录一下。当然,他不仅限于这种需求,比如在部署后端Web的时候,需要的一些静态资源,比如一些模板、css、js、图片等文件,也可以通过这样的方式打包到一个二进制文件中。

embed介绍

首先,embedgo 1.16才有的新特性,使用方法非常简单,通过 //go:embed指令,在打包时将文件内嵌到程序中。

官方文档:https://pkg.go.dev/embed

快速开始

文件结构

.
├── go.mod
├── main.go
└── resources
    └── hello.txt

代码:

package main

import (
    _ "embed"
    "fmt"
)

//embed指令↓
//go:embed resources/hello.txt
var s string

func main() {
    fmt.Println(s)
}

//输出:
//hello embed!

嵌入为字符串

快速开始就是嵌入为字符串的例子,不再多赘述

嵌入为byte slice

可以直接以二进制形式嵌入,即嵌入为 byte slice

同样时快速开始里面的文件结构

我们将代码改成如下:

package main

import (
    _ "embed"
    "fmt"
)

//go:embed resources/hello.txt
var b []byte

func main() {
    fmt.Println(string(b[0]))
    fmt.Println(string(b))
}

//输出:
//h
//hello embed!

嵌入为embed.FS

你甚至能嵌入一个文件系统,此时,你能够读取到目录树和文件树,embed.FS对外存在以下方法:

// Open 打开要读取的文件,并返回文件的fs.File结构.
func (f FS) Open(name string) (fs.File, error)

// ReadDir 读取并返回整个命名目录
func (f FS) ReadDir(name string) ([]fs.DirEntry, error)

// ReadFile 读取并返回name文件的内容.
func (f FS) ReadFile(name string) ([]byte, error)

映射单个/多个文件

文件结构:

.
├── go.mod
├── main.go
└── resources
    ├── hello1.txt
    └── hello2.txt

代码:

package main

import (
    "embed"
    _ "embed"
    "fmt"
)

//go:embed resources/hello1.txt
//go:embed resources/hello2.txt
var f embed.FS

func main() {
    hello1, _ := f.ReadFile("resources/hello1.txt")
    fmt.Println(string(hello1))
    hello2, _ := f.ReadFile("resources/hello2.txt")
    fmt.Println(string(hello2))
}

//输出:
//hello1
//hello2

映射目录

文件结构

.
├── go.mod
├── main.go
└── resources
    ├── dir1
    │   └── dir1.txt
    ├── dir2
    │   ├── dir2.txt
    │   └── dir3
    │       └── dir3.txt
    ├── hello1.txt
    └── hello2.txt

代码:

package main

import (
    "embed"
    _ "embed"
    "fmt"
)

//go:embed resources/*
var f embed.FS

func main() {
    hello1, _ := f.ReadFile("resources/hello1.txt")
    fmt.Println(string(hello1))
    hello2, _ := f.ReadFile("resources/hello2.txt")
    fmt.Println(string(hello2))
    dir1, _ := f.ReadFile("resources/dir1/dir1.txt")
    fmt.Println(string(dir1))
    dir2, _ := f.ReadFile("resources/dir2/dir2.txt")
    fmt.Println(string(dir2))
    dir3, _ := f.ReadFile("resources/dir2/dir3/dir3.txt")
    fmt.Println(string(dir3))
}

//输出:
//hello1
//hello2
//dir1
//dir2
//dir3
最后修改:2022 年 01 月 08 日
如果觉得我的文章对你有用,请随意赞赏