使用Go Embed

文摘   2024-10-10 16:40   上海  


go:embed功能简化了在Go应用程序中包含静态资源的过程。通过在编译时嵌入文件和目录,您可以创建更便携和自包含的二进制文件。

随着 Go 1.16[1] 的发布,go:embed被引入。这个新的代码注释(我们称之为指令)允许您将静态文件和文件夹嵌入到Go二进制文件中。如果您正在构建需要提供静态内容的Web服务器或需要配置文件的命令行工具,go:embed通过消除对外部文件处理的需求来简化这个过程。这也意味着您的二进制文件包含了发布代码所需的一切。非常强大!

什么是go:embed?

go:embed指令告诉Go编译器在构建时将文件和文件夹包含到编译后的二进制文件中。这意味着您的应用程序可以直接从内存访问这些资源,而无需在运行时从磁盘读取。

要使用go:embed,您需要Go 1.16或更高版本。以下是如何嵌入单个文件的简单示例:

首先,创建一个名为message.txt的文本文件。它可以包含任何内容 - 比如:

hello from bytesizego!

然后在main.go中编写以下代码

package main

import (
    _ "embed"
    "fmt"
)

//go:embed message.txt
var message string

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

在这个非常小的程序中,我们:

• 导入embed包的空白标识符_以启用go:embed指令。

• 使用//go:embed message.txt指令指定要嵌入的文件。

• 添加一个message变量来保存message.txt的内容作为字符串。

正如您所期望的,这个程序输出:

hello from bytesizego!

嵌入多个文件

让我们稍微复杂一点:

package main

import (
    "embed"
    "fmt"
)

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

func main() {
    files, _ := messages.ReadDir("messages")
    for _, file := range files {
        data, _ := messages.ReadFile("messages/" + file.Name())
        fmt.Printf("File: %s\nContent: %s\n\n", file.Name(), string(data))
    }
}

这里:

• 我们使用embed.FS来嵌入多个文件。

ReadDirReadFile方法允许我们与嵌入的文件交互。

嵌入目录

您还可以嵌入整个文件夹:

package main

import (
    "embed"
    "fmt"
)

//go:embed static/*
var staticFiles embed.FS

func main() {
    data, _ := staticFiles.ReadFile("static/index.html")
    fmt.Println(string(data))
}

提示: 在嵌入目录时,ReadFile中指定的路径是相对于嵌入根目录的。

使用go embed创建Web应用

非常简单!

package main

import (
    "embed"
    "net/http"
)

//go:embed static/*
var staticFiles embed.FS

func main() {
    http.Handle("/", http.FileServer(http.FS(staticFiles)))
    http.ListenAndServe(":8080", nil)
}

运行程序,现在您可以通过 http://localhost:8080/[2] 访问您嵌入的静态文件。

使用go embed将文件嵌入到结构体中

也许您想嵌入一些内容以便稍后在程序中使用。将它放在结构体上可能是您想要的。这对于配置可能很有用。

package main

import (
    "embed"
    "fmt"
)

//go:embed templates/home.html
var homeTemplate string

//go:embed templates/about.html
var aboutTemplate string

type Templates struct {
    Home  string
    About string
}

func main() {
    t := Templates{
        Home:  homeTemplate,
        About: aboutTemplate,
    }
    fmt.Println("Home Template:", t.Home)
    fmt.Println("About Template:", t.About)
}

使用go Embed嵌入图像和PDF

如果您正在处理非文本文件(如图像或PDF),您应该使用字节切片:

package main

import (
    _ "embed"
    "fmt"
)

//go:embed image.jpg
var imageData []byte

func main() {
    fmt.Printf("Image size: %d bytes\n", len(imageData))
}

对此要小心!这里有一些限制:

  • 文件大小: 嵌入大文件可能会显著增加您的二进制文件大小。
  • 文件更改: 对嵌入文件的更改需要重新编译。

总结

go embed非常棒!我很少看到它被使用,但现在我经常使用它,特别是在创建Web应用时。


参考链接

  1. Go 1.16: https://go.dev/doc/go1.16
  2. http://localhost:8080/
  3. 我们的其他博客: https://www.bytesizego.com/blog
  4. 加入我们的邮件列表: https://www.bytesizego.com/golang-jobs

幻想发生器
图解技术本质
 最新文章