Go 开发中的go:embed应用与最佳实践

go:embed 使用介绍

go:embedGo 语言的一项编译器指令,它允许在编译时将任意文件或目录嵌入到 Go 的二进制文件中。通过这种方式,开发者可以在不依赖外部文件的情况下直接在代码中访问这些资源,从而提高了程序的独立性和资源管理的灵活性。

特点

  • 文件嵌入类型: 对于单个文件,go:embed 可以将其嵌入为字符串 (string) 或字节切片 ([]byte)。对于多个文件或目录,则可以嵌入为文件系统 (embed.FS)。
  • 灵活性: 即使嵌入的文件变量未被显式使用,只要导入了 embed 包,文件仍然会被嵌入。
  • 语法要求: go:embed 指令必须紧跟在要嵌入文件的变量声明之前,并且该变量必须是 string[]byteembed.FS 类型,其他类型(如自定义类型)不支持。

使用方法

go:embed 的用法非常简单,以下是几种常见的应用场景:

import "embed"

//go:embed mobile.txt
var mobile string

//go:embed hello.txt
var contentBytes []byte

//go:embed hello.txt
var fileFS embed.FS

在上述示例中,mobile.txt 文件被嵌入到 mobile 字符串中,hello.txt 文件被嵌入为字节切片,而 fileFS 则作为文件系统,通过 fileFS.ReadFile("hello.txt") 来读取文件内容。

嵌入为字符串

适合嵌入小型的文本文件,如配置文件、模板等。

package main
import (
    _ "embed"
    "fmt"
)

//go:embed hello.txt
var pfinal string

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

嵌入为字节切片

适合嵌入非文本文件,如图片、字体等二进制数据。

package main
import (
    _ "embed"
    "fmt"
)

//go:embed hello.txt
var pfinal []byte

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

嵌入为 embed.FS

适合嵌入多个文件或整个目录,嵌入后可以使用 embed.FS 提供的接口来读取文件。

package main
import (
    _ "embed"
    "embed"
    "fmt"
)

//go:embed hello.txt
var pfinal embed.FS

func main() {
    data, _ := pfinal.ReadFile("hello.txt")
    fmt.Println(string(data))
}

多文件嵌入

go:embed 支持在 embed.FS 上嵌入多个文件,多个文件可以通过多行 go:embed 指令来实现(注意 string[]byte 不能有多个 go:embed 指令)。

//go:embed pfinal.txt
//go:embed hello.txt
var pfinal embed.FS

func main() {
    data, _ := pfinal.ReadFile("pfinal.txt")
    fmt.Println(string(data))
    
    data, _ = pfinal.ReadFile("hello.txt")
    fmt.Println(string(data))
}

嵌入目录

通过 go:embed,我们还可以嵌入整个目录,除了以 ._ 开头的文件默认不被嵌入之外,其他文件都会嵌入。

//go:embed pfinal/*
var pfinal embed.FS

func main() {
    data, _ := pfinal.ReadFile("pfinal/.pfinal.txt")
    fmt.Println(string(data))
}

如果需要嵌入以 ._ 开头的文件,必须明确使用通配符,例如 go:embed p/*。注意通配符不具备递归嵌入的功能,如果要嵌入子文件夹,需要在子文件夹中也使用通配符。

只读限制

嵌入的文件内容是只读的,不能在运行时修改这些嵌入的文件。embed.FS 作为只读的虚拟文件系统,支持基本的文件读取操作,但不支持写入。因此,多个 Goroutine 可以并发访问而不会出现竞争条件。

type FS
    func (f FS) Open(name string) (fs.File, error)
    func (f FS) ReadDir(name string) ([]fs.DirEntry, error)
    func (f FS) ReadFile(name string) ([]byte, error)

文件模式匹配

go:embed 指令中可以指定文件夹路径,如果仅指定文件夹路径,除 ._ 开头的文件以外,所有文件都会被嵌入,且嵌入操作是递归的。如果希望嵌入特定文件,或者嵌入以 ._ 开头的文件,必须使用通配符 *

  • 嵌入多个文件:

    //go:embed "hello.txt" "hello-2.txt"
    var f embed.FS
  • 嵌入当前目录的所有文件(除了 ._ 开头的文件):

    //go:embed *
    var f embed.FS

示例:嵌入数据并读取

以下是一个嵌入二进制文件(如数据库文件)的示例:

package main

import (
    "embed"
    "fmt"
)

//go:embed phone.dat
var fsContent embed.FS

func main() {
    data, err := fsContent.ReadFile("phone.dat")
    if err != nil {
        panic(err)
    }
    fmt.Println(data)
}

该示例中,phone.dat 文件被嵌入到 fsContent 中,可以在程序运行时直接读取该文件内容。

标签: Go

相关文章

在 Go 项目中使用 LevelDB 进行数据存储

LevelDB 是一个由 Google 开发的高性能键值存储库,广泛应用于需要快速读写操作的场景。本文将介绍如何在 Go 项目中使用 LevelDB 作为数据存储,并通过示例代码展示如何初始化数...

详解Go语言依赖注入工具wire最佳实践介绍与使用

wire是一个强大的依赖注入工具,通过代码生成的方式实现了高效的依赖注入。本文详细介绍了wire的入门级和高级使用技巧,并通过示例代码展示了其强大的功能。无论是简单的依赖注入,还是复杂的依赖图生...

Go语言中copy命令讲解 切片之间复制元素

在Go语言中,copy函数是一个非常常用的内置函数,用于在切片(slice)之间复制元素。理解copy函数的用法和机制对于高效处理数据操作至关重要1. copy函数的基本用法copy函数的基本语...

深入理解 Go 语言中的 goto:用法与最佳实践

在学习编程语言时,goto 一直是一个颇具争议的概念。它常常因为“跳跃式”的行为被认为会让代码混乱且难以维护,但在 Go 语言中,goto 被保留并提供了一些实际的应用场景。今天我们将深入探讨 ...

Go并发编程与调度器及并发模式详解

Go语言以其简洁的语法和强大的并发能力,成为现代网络编程和微服务架构的热门选择。本文将深入探讨Go的并发编程模型,调度器的工作机制,以及多种并发模式的实现和应用,帮助开发者更好地理解并发编程的设...

Go语言中sync.Pool详解

sync.Pool 是 Go 语言标准库中的一个数据结构,用于提供高效的对象池。它的主要作用是缓存临时对象,以减少内存分配和垃圾回收的开销。sync.Pool 特别适合用于存储短生命周期的对象,...

图片Base64编码

CSR生成

图片无损放大

图片占位符

Excel拆分文件