Inicio 🧑🏼‍💻 Juanse Tech
img of Archivos embebidos en Go

Publicado el

- 3 min read

Archivos embebidos en Go


Sé que, como yo, has pasado por este problema: Necesitas acceder al contenido de X archivo en tu programa de Go.

Lo primero que se nos viene a la mente es abrirlo de la manera clásica, con os.ReadFile, y no hay nada malo en esto, es perfectamente funcional, pero hoy te vengo a mostrar otra alternativa con varias ventajas: Archivos embebidos.

En ocasiones se nos dificulta la manera “clásica” por el cambio de rutas de los archivos entre scopes de nuestra aplicación, ya sea en local, en la nube, en tu hosting, etc. El problema lo vas a encontrar cuando despliegas únicamente el ejecutable que genera Go con el go build, este ejecutable no incluye nada más que el código, si llamas a algún archivo estático desde ese ejecutable y te llevas solo el ejecutable para otro lado, tu parte de código que accede a ese archivo estático va a fallar.

Esto se soluciona con go embed, una utilidad que nos permite embeber archivos al ejecutable de Go y así olvidarnos del problema de rutas relativas/absolutas o archivos no encontrados.

Imagina que en tu aplicación, necesitas acceder a un json que se encuentra en un archivo estático, un json por poner un ejemplo, pero puede ser casi cualquier tipo de archivo, miremos la comparación entre ambas formas de obtener el archivo dentro de nuestro programa:

os.ReadFile

Con la forma clásica haríamos esto:

   package main

import (
	"encoding/json"
	"fmt"
	"io"
	"os"
)

type User struct {
	ID   int
	Name string
}

func main() {
	file, err := os.Open("./user.json")
	if err != nil {
		panic(err)
	}
	defer file.Close()

	bytes, err := io.ReadAll(file)
	if err != nil {
		panic(err)
	}

	var user User
	if err := json.Unmarshal(bytes, &user); err != nil {
		panic(err)
	}

	fmt.Printf("%+v\n", user)
}

Y este código funciona de manera maravillosa, cuando haces, go run main.go abre y lee el archivo, además de hacer el unmarshal a un objeto de tipo User.

Cuando buildeas la aplicación y envías solamente el ejecutable a otro lado va a fallar, porque no va a encontrar el archivo nunca, a no ser de que lo lleves contigo.

   panic: open./ user.json: no such file or directory

goroutine 1[running]:
main.main()
  / Users / jvillega / Documents / blog - embed / main.go: 18 + 0x185

Go embed

Como mencioné en la introducción, go embed te permite embeber archivos en el build de la aplicación, lo logras de la siguiente manera:

   //go:embed filePath
var n []byte

Esta es la parte que embebe el archivo, filePath es la ruta del archivo relativa a donde lo llames y esta línea de go:embed siempre debe ir encima de una variable definida fuera de cualquier scope (Fuera de funciones).

Con nuestro ejemplo del json anterior, nos quedaría el siguiente código:

   package main

import (
	_ "embed"
	"encoding/json"
	"fmt"
)

type User struct {
	ID   int
	Name string
}

//go:embed user.json
var file []byte

func main() {
	var user User
	if err := json.Unmarshal(file, &user); err != nil {
		panic(err)
	}

	fmt.Printf("%+v\n", user)
}

Ahora, nuestro archivo está embebido, cuando hacemos go build, y nos llevamos solo el ejecutable, el programa siempre funciona

   output: {ID:1 Name:Gopher}

Y nunca nos tira un error, porque el archivo lo tiene embebido, no lo debe buscar en ningún otro lado.

Sin duda una utilidad que nos ahorra muchos dolores de cabeza 😉

Juanse

Hey 👋🏻! Este artículo fue escrito por Juanse

Un adicto a escribir software que tiene pasión por la enseñanza 🧑🏼‍💻

Si te gusto el artículo o te fue útil, no dudes de compartirlo 😃