Paquete embed en Go
El paquete embed en Go permite incrustar archivos y directorios en un binario Go. Este documento explora en profundidad sus características y casos de uso prácticos.
1. Conceptos Básicos
1.1 Directiva go:embed
La directiva //go:embed es fundamental para especificar qué archivos se deben incrustar.
// filepath: ejemplos/embed/basic/main.go
package main
import (
"embed"
"fmt"
)
//go:embed hello.txt
var contenido string
//go:embed config.json
var configBytes []byte
//go:embed templates/*
var templates embed.FS
func main() {
fmt.Printf("Contenido del archivo: %s\n", contenido)
fmt.Printf("Bytes de configuración: %d bytes\n", len(configBytes))
}
// filepath: ejemplos/embed/tipos/main.go
package main
import (
"embed"
"fmt"
)
// String para archivos de texto
//go:embed datos/texto.txt
var textoPlano string
// []byte para archivos binarios
//go:embed datos/imagen.png
var imagenBytes []byte
// embed.FS para múltiples archivos
//go:embed datos/* templates/*
var filesystem embed.FS
func main() {
// Trabajar con string
fmt.Printf("Contenido texto: %s\n", textoPlano)
// Trabajar con []byte
fmt.Printf("Tamaño imagen: %d bytes\n", len(imagenBytes))
// Trabajar con embed.FS
archivos, _ := filesystem.ReadDir("datos")
for _, archivo := range archivos {
fmt.Printf("Archivo encontrado: %s\n", archivo.Name())
}
}
// filepath: ejemplos/embed/config/main.go
package main
import (
"embed"
"encoding/json"
"fmt"
"log"
)
//go:embed configs/*.json
var configFiles embed.FS
type Config struct {
Database struct {
Host string `json:"host"`
Port int `json:"port"`
User string `json:"user"`
Password string `json:"password"`
} `json:"database"`
Server struct {
Port int `json:"port"`
Hosts []string `json:"hosts"`
TLS bool `json:"tls"`
} `json:"server"`
}
func LoadConfig(env string) (*Config, error) {
fileName := fmt.Sprintf("configs/%s.json", env)
data, err := configFiles.ReadFile(fileName)
if (err != nil) {
return nil, fmt.Errorf("error leyendo config: %w", err)
}
var config Config
if err := json.Unmarshal(data, &config); err != nil {
return nil, fmt.Errorf("error parseando config: %w", err)
}
return &config, nil
}
func main() {
// Cargar configuración para diferentes entornos
environments := []string{"development", "staging", "production"}
for _, env := range environments {
config, err := LoadConfig(env)
if err != nil {
log.Printf("Error cargando config %s: %v", env, err)
continue
}
fmt.Printf("=== Configuración: %s ===\n", env)
fmt.Printf("Database Host: %s\n", config.Database.Host)
fmt.Printf("Server Port: %d\n", config.Server.Port)
}
}
// filepath: ejemplos/embed/assets/main.go
package main
import (
"embed"
"fmt"
"image"
_ "image/png"
"io/fs"
)
//go:embed assets/*
var assets embed.FS
type AssetManager struct {
fs embed.FS
}
func NewAssetManager(filesystem embed.FS) *AssetManager {
return &AssetManager{fs: filesystem}
}
func (am *AssetManager) ListAssets(dir string) ([]string, error) {
var files []string
entries, err := am.fs.ReadDir(dir)
if err != nil {
return nil, fmt.Errorf("error listando directorio: %w", err)
}
for _, entry := range entries {
if !entry.IsDir() {
files = append(files, entry.Name())
}
}
return files, nil
}
func (am *AssetManager) LoadImage(path string) (image.Image, error) {
file, err := am.fs.Open(path)
if err != nil {
return nil, fmt.Errorf("error abriendo imagen: %w", err)
}
defer file.Close()
img, _, err := image.Decode(file)
if err != nil {
return nil, fmt.Errorf("error decodificando imagen: %w", err)
}
return img, nil
}
func main() {
manager := NewAssetManager(assets)
// Listar assets
files, err := manager.ListAssets("assets")
if (err != nil) {
panic(err)
}
fmt.Println("Assets encontrados:")
for _, file := range files {
fmt.Printf("- %s\n", file)
}
// Cargar una imagen
img, err := manager.LoadImage("assets/logo.png")
if (err != nil) {
panic(err)
}
bounds := img.Bounds()
fmt.Printf("\nDimensiones de la imagen: %dx%d\n",
bounds.Max.X, bounds.Max.Y)
}
Ejemplos de Uso
- Incrustar un archivo de texto en una cadena
- Descripción: El contenido del archivo
mensaje.txtse incrusta en la variablemensaje. - Código:
package main import ( "embed" "fmt" ) //go:embed mensaje.txt var mensaje string func main() { fmt.Println(mensaje) }
- Descripción: El contenido del archivo
- Incrustar un archivo binario en un slice de bytes
- Descripción: El contenido del archivo
imagen.pngse incrusta en la variableimagen. - Código:
package main import ( "embed" "fmt" ) //go:embed imagen.png var imagen []byte func main() { fmt.Printf("La imagen tiene %d bytes\n", len(imagen)) }
- Descripción: El contenido del archivo
- Incrustar múltiples archivos en un sistema de archivos virtual
- Descripción: Todos los archivos en el directorio
templatesse incrustan en la variabletemplatesde tipoembed.FS. - Código:
package main import ( "embed" "fmt" ) //go:embed templates/* var templates embed.FS func main() { data, err := templates.ReadFile("templates/template1.html") if err != nil { panic(err) } fmt.Println(string(data)) }
- Descripción: Todos los archivos en el directorio
Explicación
//go:embed archivo.txt: Incrusta el contenido dearchivo.txten una variable.string: Incrusta un archivo de texto como una cadena.[]byte: Incrusta un archivo binario como un slice de bytes.embed.FS: Incrusta múltiples archivos o directorios en un sistema de archivos virtual.
Estas herramientas proporcionan una manera poderosa y conveniente de incluir recursos estáticos directamente en los binarios de tu aplicación Go, eliminando la necesidad de llevar archivos externos junto con tu ejecutable.
Si tienes más preguntas o necesitas más detalles sobre el uso del paquete embed, ¡háblame! Estoy aquí para ayudarte.