Distribusi program paling nyaman ketika seluruh kebutuhannya berada dalam satu binary: template, berkas konfigurasi contoh, sampai aset halaman web. Package embed menyematkan berkas statis ke dalam binary pada saat kompilasi, sehingga program berjalan tanpa bergantung pada berkas di disk. Chapter ini menyematkan satu berkas teks dan satu folder penuh, lalu membacanya kembali lewat API sistem berkas standar.
Menyematkan String dengan import _ “embed” #
Bentuk paling sederhana menyematkan isi satu berkas ke variabel string. Directive //go:embed ditulis tepat di atas deklarasi variabel, dan package embed diimpor secara kosong karena yang dipakai adalah efek kompilasinya, bukan identifier-nya:
import _ "embed"
//go:embed pesan.txt
var pesan stringSetelah kompilasi, variabel pesan berisi seluruh isi pesan.txt sebagai string biasa — tidak ada pembacaan disk saat program berjalan. Bentuk []byte juga didukung untuk data biner seperti gambar.
embed.FS untuk Banyak Berkas #
Berkas banyak sekaligus dikelola tipe embed.FS — sistem berkas virtual hanya-baca yang aman dipakai dari banyak goroutine. Pola direktori mengambil seluruh isi folder:
//go:embed statis/*
var statis embed.FSembed.FS memenuhi interface fs.FS dari package io/fs, sehingga seluruh API standar berlaku: ReadDir mendaftar entri (terurut menurut nama), ReadFile mengambil isi berkas, Open membuka berkas sebagai fs.File, dan fs.WalkDir menelusuri pohon direktori. Fungsi fs.Sub memotong awalan path bila perlu.
Aturan Pola //go:embed #
Pola pada directive mengikuti aturan ketat. Path ditulis relatif terhadap folder paket yang berisi berkas .go; path absolut dan .. tidak diizinkan sehingga tidak ada penyematan dari luar modul. Pola * mengambil semua entri kecuali yang berawalan . atau _; menyebut nama direktori mengambil seluruh isinya secara rekursif.
embed vs os.ReadFile #
| Aspek | embed | os.ReadFile |
|---|---|---|
| Sumber data | di dalam binary | disk saat program berjalan |
| Binary mandiri | ya — cukup satu berkas program | tidak — berkas wajib ikut terdistribusi |
| Perubahan isi | perlu kompilasi ulang | cukup ganti berkas |
| Cocok untuk | template, aset, konfigurasi bawaan | data pengguna, berkas besar |
embed mengutamakan kemandirian binary; os.ReadFile mengutamakan isi yang dapat berubah tanpa kompilasi ulang. Chapter Membaca Berkas
membahas jalur os secara penuh.
Melayani Berkas dengan http.FS #
Karena embed.FS adalah fs.FS, package net/http dapat langsung menyajikannya lewat http.FS:
mux.Handle("GET /statis/", http.StripPrefix("/statis/", http.FileServer(http.FS(statis))))Pola di atas mendaftarkan rute GET /statis/ pada ServeMux — pola method yang tersedia sejak Go 1.22. Chapter File Server
membedah penyajian berkas statis lebih jauh.
Program Utuh #
Berkas embed-demo.go menyematkan dua sumber sekaligus: pesan.txt dan folder statis/. Isi pesan.txt:
Halo dari berkas yang ikut terkompilasi ke dalam binary!Isi statis/tentang.md:
# Tentang Aplikasi
Aplikasi contoh untuk chapter embed.
Berkas ini ikut terkompilasi ke dalam binary.Isi statis/gaya.css:
body {
font-family: sans-serif;
margin: 2rem auto;
max-width: 40rem;
}
h1 {
color: #1a73e8;
}Program lengkapnya:
package main
import (
"embed"
"fmt"
"io/fs"
)
//go:embed pesan.txt
var pesan string
//go:embed statis/*
var statis embed.FS
// embed.FS memenuhi interface fs.FS sehingga API io/fs standar bisa dipakai.
var _ fs.FS = statis
func main() {
// String tertanam tersedia sebagai nilai biasa, tanpa membaca disk.
fmt.Println("pesan :", pesan)
// ReadDir mendaftar isi direktori tertanam, terurut menurut nama.
entri, err := statis.ReadDir("statis")
if err != nil {
fmt.Println("gagal membaca direktori:", err)
return
}
for _, e := range entri {
fmt.Println("entri :", e.Name())
}
// fs.ReadFile membaca satu berkas dari sistem berkas tertanam.
isi, err := fs.ReadFile(statis, "statis/tentang.md")
if err != nil {
fmt.Println("gagal membaca berkas:", err)
return
}
fmt.Printf("tentang: %d byte\n%s\n", len(isi), isi)
}Jalankan program dari folder chapter:
go run embed-demo.goOutput yang Dihasilkan:
pesan : Halo dari berkas yang ikut terkompilasi ke dalam binary!
entri : gaya.css
entri : tentang.md
tentang: 102 byte
# Tentang Aplikasi
Aplikasi contoh untuk chapter embed.
Berkas ini ikut terkompilasi ke dalam binary.Mari kita telaah baris demi baris program di atas:
- Baris 4-6: tiga package diimpor —
embeduntuk tipeFS,fmtuntuk mencetak, danio/fsuntuk API berkas standar. - Baris 9-10: directive
//go:embed pesan.txtmenyematkan isi berkas ke variabelpesanbertipe string. - Baris 12-13: pola
statis/*menyematkan seluruh berkas di folderstatiske variabelstatisbertipeembed.FS. - Baris 16: deklarasi
var _ fs.FS = statismenegaskan pada saat kompilasi bahwaembed.FSmemenuhi interfacefs.FS. - Baris 20: string tertanam dicetak seperti nilai biasa — tanpa operasi berkas.
- Baris 23-30:
ReadDirmendaftar entri folder tertanam;gaya.cssdantentang.mdmuncul terurut menurut nama. - Baris 33-38:
fs.ReadFilemembacastatis/tentang.mdsampai 102 byte, lalu isi dan panjangnya dicetak.
Referensi #
- Dokumentasi package embed — directive dan aturan pola.
- embed.FS — sistem berkas tertanam beserta methodnya.
- Dokumentasi package io/fs
— interface yang dipenuhi
embed.FS.
Perjalanan section Standard Library tuntas: dua belas package — dari fmt yang mencetak, os dan io yang berbicara dengan sistem, sampai embed yang menggabungkan semuanya dalam satu binary. Package lain akan menyusul seiring kebutuhan: encoding/json saat bertukar data, net/http saat melayani permintaan. Seluruhnya berdiri di atas fondasi yang baru Anda kuasai.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
embed-demo.go
Unduh berkaspackage main
import (
"embed"
"fmt"
"io/fs"
)
//go:embed pesan.txt
var pesan string
//go:embed statis/*
var statis embed.FS
// embed.FS memenuhi interface fs.FS sehingga API io/fs standar bisa dipakai.
var _ fs.FS = statis
func main() {
// String tertanam tersedia sebagai nilai biasa, tanpa membaca disk.
fmt.Println("pesan :", pesan)
// ReadDir mendaftar isi direktori tertanam, terurut menurut nama.
entri, err := statis.ReadDir("statis")
if err != nil {
fmt.Println("gagal membaca direktori:", err)
return
}
for _, e := range entri {
fmt.Println("entri :", e.Name())
}
// fs.ReadFile membaca satu berkas dari sistem berkas tertanam.
isi, err := fs.ReadFile(statis, "statis/tentang.md")
if err != nil {
fmt.Println("gagal membaca berkas:", err)
return
}
fmt.Printf("tentang: %d byte\n%s\n", len(isi), isi)
}
statis/gaya.css
Unduh berkasbody {
font-family: sans-serif;
margin: 2rem auto;
max-width: 40rem;
}
h1 {
color: #1a73e8;
}