Ce face embed.FS
Directiva //go:embed, pusă chiar deasupra unei variabile la nivel de pachet, îi spune compilatorului să copieze fișierele în executabil. Variabila poate fi string sau []byte (pentru un singur fișier) sau embed.FS (pentru mai multe fișiere și directoare). Pentru string și []byte scrii import _ "embed".
embed.FS implementează fs.FS, deci îl folosești cu fs.ReadFile, fs.ReadDir, fs.WalkDir, template.ParseFS și http.FileServerFS. Metodele proprii sunt ReadFile, ReadDir și Open. Conținutul este doar pentru citire.
Căile sunt relative la directorul fișierului .go și nu pot conține ... Fișierele care încep cu . sau _ sunt sărite când incluzi un director, dacă nu folosești prefixul all: (//go:embed all:static). Un model care nu găsește niciun fișier oprește compilarea.
Parametri
| Parametru | Descriere |
|---|---|
modele |
După //go:embed: nume de fișiere, directoare sau modele cu *, separate prin spații. |
Ce returnează
Nu se aplică: variabila primește conținutul la compilare.
Exemple
Exemplul 1: Programul își include propriul cod sursă
Ca exemplul să poată rula oriunde, includem chiar fișierul main.go, singurul care sigur există lângă program.
package main
import (
"embed"
"fmt"
"io/fs"
"strings"
)
//go:embed main.go
var fisiere embed.FS
func main() {
intrari, _ := fs.ReadDir(fisiere, ".")
for _, e := range intrari {
fmt.Println("fișier inclus:", e.Name())
}
sursa, err := fisiere.ReadFile("main.go")
if err != nil {
fmt.Println("eroare:", err)
return
}
primul, _, _ := strings.Cut(string(sursa), "\n")
fmt.Println("primul rând:", primul)
_, err = fisiere.ReadFile("lipsa.txt")
fmt.Println(err)
}
Rezultat
fișier inclus: main.go
primul rând: package main
open lipsa.txt: file does not exist
Exemplul 2: Un singur fișier ca string
package main
import (
_ "embed"
"fmt"
"strings"
)
//go:embed main.go
var sursa string
func main() {
fmt.Println("rânduri în sursă:", strings.Count(sursa, "\n"))
fmt.Println("conține //go:embed:", strings.Contains(sursa, "//go:embed"))
}
Rezultat
rânduri în sursă: 14
conține //go:embed: true
Exemplul 3: Site static și șabloane într-un singur executabil
Structura proiectului: main.go, static/stil.css, static/logo.png, sabloane/index.html. După go build, executabilul poate fi copiat singur pe server.
package main
import (
"embed"
"html/template"
"io/fs"
"log"
"net/http"
)
//go:embed static sabloane/*.html
var continut embed.FS
func main() {
pagini := template.Must(template.ParseFS(continut, "sabloane/*.html"))
fs.WalkDir(continut, ".", func(cale string, d fs.DirEntry, err error) error {
log.Println("inclus:", cale)
return nil
})
http.Handle("GET /static/", http.FileServerFS(continut))
http.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
pagini.ExecuteTemplate(w, "index.html", map[string]string{"Oras": "Iași"})
})
log.Fatal(http.ListenAndServe(":8080", nil))
}
Rezultat în terminal (serverul rămâne pornit)
2025/03/14 10:00:00 inclus: .
2025/03/14 10:00:00 inclus: sabloane
2025/03/14 10:00:00 inclus: sabloane/index.html
2025/03/14 10:00:00 inclus: static
2025/03/14 10:00:00 inclus: static/logo.png
2025/03/14 10:00:00 inclus: static/stil.css
Greșeli frecvente
- Pui
//go:embeddeasupra unei variabile locale (în interiorul unei funcții). Directiva funcționează doar pentru variabile de la nivelul pachetului. - Lași un rând gol sau un comentariu între directivă și variabilă, ori scrii
// go:embedcu spațiu. Directiva este ignorată sau compilarea eșuează. - Te aștepți ca fișierele
.envsau_partial.htmlsă fie incluse cu//go:embed sabloane. Fișierele care încep cu.sau_sunt sărite; foloseșteall:sabloane. - Modifici fișierele de pe disc și te aștepți ca programul să vadă schimbarea. Conținutul este cel de la compilare; recompilează.
Comenzi înrudite
os.DirFS: Transformă un director de pe disc într-un fs.FS, sistemul de fișiere abstract din Go.os.CopyFS: Copiază tot conținutul unui sistem de fișiere (fs.FS) într-un director de pe disc.filepath.WalkDir: Parcurge recursiv un director și apelează o funcție pentru fiecare fișier și subdirector, în ordine alfabetică.