Vkládání dat přímo do spustitelných souborů vytvářených překladačem jazyka Go

1. 8. 2023
Doba čtení: 17 minut

Sdílet

 Autor: Go lang
Ukážeme si užitečný balíček, který v kooperaci s překladačem a linkerem jazyka Go umožňuje vkládat data do výsledného spustitelného souboru. To zjednodušuje nasazení aplikace a zmenšuje míru „instalačních“ chyb.

Obsah

1. Vkládání dat přímo do spustitelných souborů vytvářených překladačem jazyka Go

2. Vložení krátkého řetězce do výsledného spustitelného souboru

3. Korektní způsob použití balíčku embed

4. Vložení delšího víceřádkového řetězce do výsledného spustitelného souboru

5. Binární data (sekvence bajtů) vložená do výsledného spustitelného souboru

6. Pokus o vložení dat jiného typu

7. Vložené soubory a virtuální souborový systém

8. Přístup ke vloženému souboru přes virtuální souborový systém

9. Vložení rastrových dat ve formátu JPEG, export obrázku v runtime

10. Jak lze do virtuálního souborového systému přidat větší množství souborů?

11. Získání seznamu všech souborů vložených do vybraného virtuálního adresáře

12. Větší množství adresářů ve virtuálním souborovém systému

13. Závěr

14. Repositář s demonstračními příklady

15. Odkazy na Internetu

1. Vkládání dat přímo do spustitelných souborů vytvářených překladačem jazyka Go

Programovací jazyk Go je mezi vývojáři v některých oblastech (například v oblasti mikroslužeb) oblíben mj. i proto, že pro nasazení aplikace vyvinuté v Go je mnohdy nutné pouze použít jediný spustitelný soubor a příliš se nestarat o to, na jakých dalších dynamicky linkovaných knihovnách nasazovaná aplikace závisí (protože tyto závislosti v mnoha případech vůbec neexistují). To je výhodné například tehdy, pokud se aplikace nasazuje do „kontejnerizovaného“ prostředí atd. Většinou se taková aplikace konfiguruje nikoli s využitím konfiguračního souboru, ale přes proměnné prostředí, takže odpadá nutnost nasazení a správy konfiguračních souborů.

Ovšem situace je poněkud odlišná tehdy, pokud aplikace ke své činnosti vyžaduje nějaké soubory s daty. Může se jednat například o statické HTML stránky, obrázky, šablony (templates) atd. Zde již výhody nasazení celé aplikace pouhým zkopírováním jediného souboru zdánlivě mizí. Ovšem jazyk Go od verze 1.16 podporuje zajímavou a užitečnou technologii – datové soubory je totiž umožněno přidat přímo do onoho spustitelného souboru vytvářeného překladačem a linkerem jazyka Go. A navíc je možné k obsahu těchto souborů přistupovat buď přímo jakoby se jednalo o inicializované proměnné (typu řetězec či sekvence bajtů) nebo přes „virtuální“ souborový systém. A právě tuto relativně málo známou vlastnost programovacího jazyka Go si popíšeme v dnešním článku.

Poznámka: ve skutečnosti lze podobný koncept využít například i v céčku, ovšem zde se již vyžaduje znalost linkeru a výsledné řešení nebude přenositelné na jiné překladače či jiné platformy.

2. Vložení krátkého řetězce do výsledného spustitelného souboru

Do výsledného spustitelného souboru můžeme vložit řetězec, jenž je v době překladu načtený z nějakého textového souboru. Pro tento účel se před definicí proměnné použije tento speciální komentář:

//go:embed hello.txt

Například:

package main
 
import (
        "fmt"
)
 
//go:embed hello.txt
var helloMessage string
 
func main() {
        // pouziti retezce
        fmt.Println(helloMessage)
}
Poznámka: zdrojový kód tohoto příkladu je uložen na adrese https://github.com/tisnik/go-root/blob/master/article_AB/em­bed_string0.go.

Při pokusu o překlad tohoto zdrojového kódu však dojde k chybě, protože pro zpracování výše uvedeného speciálního komentáře je nutné načíst balíček embed:

./embed_string0.go:7:3: go:embed only allowed in Go files that import "embed"

Pokusme se tedy o úpravu tohoto příkladu:

package main
 
import (
        "embed"
        "fmt"
)
 
//go:embed hello.txt
var helloMessage string
 
func main() {
        // pouziti retezce
        fmt.Println(helloMessage)
}
Poznámka: zdrojový kód tohoto příkladu je uložen na adrese https://github.com/tisnik/go-root/blob/master/article_AB/em­bed_string1.go.

Ani tento způsob ovšem ve skutečnosti není zcela korektní, protože sice importujeme balíček embed, ovšem nikde ho nepoužijeme, což v Go není dovoleno (je použit jen v onom komentáři):

./embed_string1.go:4:2: "embed" imported and not used

3. Korektní způsob použití balíčku embed

Jak tedy můžeme naimportovat balíček embed, i když není přímo v kódu použit? Programovací jazyk Go vyžaduje, aby každý importovaný balíček byl skutečně využit (což jsme ostatně viděli výše), ovšem existuje zde jeden trik, jak pouze provést import bez explicitního použití (používá se například při načítání databázových driverů). Tento trik spočívá v tom, že se před jméno importovaného balíčku zadá jeho jmenný alias, který je nastavený na podtržítko:

import _ "embed"

V praxi to může vypadat následovně:

package main
 
import (
        _ "embed"
        "fmt"
)
 
//go:embed hello.txt
var helloMessage string
 
func main() {
        // pouziti retezce
        fmt.Println(helloMessage)
}
Poznámka: zdrojový kód tohoto příkladu je uložen na adrese https://github.com/tisnik/go-root/blob/master/article_AB/em­bed_string2.go.

Tento zdrojový kód je již bez problémů jak přeložitelný, tak i spustitelný:

$ go build embed_string2.go
 
$ ./embed_string2
Hello world!

O tom, že řetězec „Hello world!“ je skutečně ve spustitelném kódu použit, se lze snadno přesvědčit (i když dost primitivním způsobem):

$ strings embed_string2 | grep Hello
 
entersyscallgcBitsArenasgcpacertraceharddecommithost is downillegal seekinvalid
slotlfstack.pushmadvdontneedmheapSpecialmspanSpecialnot pollablens} value:
{releasep: m=runtime: gp=runtime:
sp=spanSetSpinesweepWaiterstimer_deletetraceStringswirep: p->m=worker mode
}, want {r1= != sweepgen  MB globals,  MB) workers= called from  failed with
flushedWork  idlethreads= is nil, not  nStackRoots= pluginpath=  s.spanclass=
span.base()= syscalltick= work.nproc=  work.nwait= , gp->status=, not
pointer-byte block (3814697265625: unknown pc GC sweep
waitGunjala_GondiHello world!

4. Vložení delšího víceřádkového řetězce do výsledného spustitelného souboru

V dalším demonstračním příkladu se do výsledného spustitelného kódu pokusíme vložit delší řetězec, který je navíc víceřádkový. Použijeme přitom klasický příklad odstavce „Lorem ipsum“:

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.

Samotný zdrojový kód příkladu se prakticky nebude lišit od příkladu předchozího, pouze použijeme jiné jméno souboru „ipsum.txt“ a jiné jméno proměnné, do které se obsah tohoto souboru automaticky přiřadí (loremIpsum):

package main
 
import (
        _ "embed"
        "fmt"
)
 
//go:embed lorem_ipsum.txt
var loremIpsum string
 
func main() {
        // pouziti retezce
        fmt.Println(loremIpsum)
}
Poznámka: zdrojový kód tohoto příkladu je uložen na adrese https://github.com/tisnik/go-root/blob/master/article_AB/em­bed_string3.go.

Proveďme kontrolní překlad a spuštění:

$ go build embed_string3.go 
 
 
 
$ ./embed_string3 
 
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.

5. Binární data (sekvence bajtů) vložená do výsledného spustitelného souboru

Kromě řetězců lze do výsledného spustitelného souboru vložit data v ještě jednom dostupném a podporovaném formátu. Jedná se o sekvenci bajtů, což je datový typ, jenž je v jazyce Go reprezentován buď jako pole bajtů (nepříliš často používáno) nebo jako řez bajtů, tj.:

[]byte

Programově je možné tuto sekvenci bajtů použít různými způsoby, například ji předat do funkce json.Unmarshal, xml.Unmarshal atd. V obou zmíněných případech má funkce pro dekódování dat ze sekvence bajtů zcela shodnou hlavičku (což samozřejmě není náhoda):

func Unmarshal(data []byte, v any) error

Vložení binárních dat (a nikoli řetězců) do výsledného spustitelného souboru je snadné, jak to ostatně ukazuje následující demonstrační příklad:

package main
 
import (
        _ "embed"
        "fmt"
)
 
//go:embed lorem_ipsum.txt
var loremIpsum []byte
 
func main() {
        // pouziti retezce
        fmt.Println(loremIpsum)
}

Po překladu a spuštění tohoto příkladu se zobrazí obsah jednotlivých bajtů v řezu:

$ go run embed_binary1.go
 
[76 111 114 101 109 32 105 112 115 117 109 32 100 111 108 111 114 32 115 105
116 32 97 109 101 116 44 32 99 111 110 115 101 99 116 101 116 117 114 32 97 100
105 112 105 115 99 105 110 103 32 101 108 105 116 44 32 115 101 100 32 100 111
32 101 105 117 115 109 111 100 32 116 101 109 112 111 114 10 105 110 99 105 100
105 100 117 110 116 32 117 116 32 108 97 98 111 114 101 32 101 116 32 100 111
108 111 114 101 32 109 97 103 110 97 32 97 108 105 113 117 97 46 32 85 116 32
101 110 105 109 32 97 100 32 109 105 110 105 109 32 118 101 110 105 97 109 44
32 113 117 105 115 10 110 111 115 116 114 117 100 32 101 120 101 114 99 105 116
97 116 105 111 110 32 117 108 108 97 109 99 111 32 108 97 98 111 114 105 115 32
110 105 115 105 32 117 116 32 97 108 105 113 117 105 112 32 101 120 32 101 97
32 99 111 109 109 111 100 111 32 99 111 110 115 101 113 117 97 116 46 10 68 117
105 115 32 97 117 116 101 32 105 114 117 114 101 32 100 111 108 111 114 32 105
110 32 114 101 112 114 101 104 101 110 100 101 114 105 116 32 105 110 32 118
111 108 117 112 116 97 116 101 32 118 101 108 105 116 32 101 115 115 101 32 99
105 108 108 117 109 32 100 111 108 111 114 101 32 101 117 10 102 117 103 105 97
116 32 110 117 108 108 97 32 112 97 114 105 97 116 117 114 46 32 69 120 99 101
112 116 101 117 114 32 115 105 110 116 32 111 99 99 97 101 99 97 116 32 99 117
112 105 100 97 116 97 116 32 110 111 110 32 112 114 111 105 100 101 110 116 44
32 115 117 110 116 32 105 110 10 99 117 108 112 97 32 113 117 105 32 111 102
102 105 99 105 97 32 100 101 115 101 114 117 110 116 32 109 111 108 108 105 116
32 97 110 105 109 32 105 100 32 101 115 116 32 108 97 98 111 114 117 109 46 10]

Zdrojový kód tohoto příkladu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article_AB/em­bed_binary1.go.

Ale převod zpět na řetězec je snadný:

package main
 
import (
        _ "embed"
        "fmt"
)
 
//go:embed lorem_ipsum.txt
var loremIpsum []byte
 
func main() {
        // pouziti retezce
        fmt.Println(string(loremIpsum))
}

S očekávaným výsledkem:

$ go run embed_binary2.go
 
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.

Zdrojový kód tohoto příkladu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article_AB/em­bed_binary2.go.

6. Pokus o vložení dat jiného typu

Zajímavé bude zjistit, co se stane ve chvíli, kdy se do výsledného spustitelného souboru pokusíme vložit data jiného typu než řetězec nebo sekvence bajtů. Vyzkoušíme si to například na tomto demonstračním příkladu:

package main
 
import (
        _ "embed"
        "fmt"
)
 
type Foo struct {
        x string
        y bool
}
 
//go:embed lorem_ipsum.txt
var loremIpsum Foo
 
func main() {
        // pouziti struktury
        fmt.Println(loremIpsum)
}

I když by to mohlo být užitečné, není tato funkcionalita překladačem Go podporována, o čemž nás překladač bude nekompromisně informovat:

$ go build embed_other_data.go 
 
# command-line-arguments
./embed_other_data.go:14:5: go:embed cannot apply to var of type Foo

Zdrojový kód tohoto příkladu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article_AB/em­bed_other_data.go.

7. Vložené soubory a virtuální souborový systém

Přímé vkládání obsahu souborů do výsledného spustitelného binárního souboru je sice potenciálně velmi užitečná funkce, ovšem standardní balíček embed programátorům nabízí ještě jednu velmi zajímavou funkcionalitu – možnost přístupu ke vloženým souborům takovým způsobem, jakoby se jednalo o virtuální souborový systém. Konkrétně je tento souborový systém dostupný přes datový typ embed.FS, který (ovšem pouze při správné inicializaci) programátorům nabízí tyto metody:

Metoda Stručný popis metody
func (f FS) Open(name string) (fs.File, error) otevření pojmenovaného souboru na virtuálním souborovém systému
func (f FS) ReadDir(name string) ([]fs.DirEntry, error) získání obsahu adresáře na virtuálním souborovém systému
func (f FS) ReadFile(name string) ([]byte, error) přečtení obsahu souboru na virtuálním souborovém systému

Samotný virtuální souborový systém (resp. typ, který ho představuje) se deklaruje a naplní takto:

//go:embed lorem_ipsum.txt
var f embed.FS

popř.:

//go:embed hello.txt
//go:embed lorem_ipsum.txt
var f embed.FS

nebo následovně:

//go:embed *.jpg
//go:embed lorem_ipsum.txt
var f embed.FS

8. Přístup ke vloženému souboru přes virtuální souborový systém

Vyzkoušejme si nyní, jak se k vloženým souborům přistupuje přes virtuální souborový systém. Strukturovaným komentářem //go:embed jméno souboru si necháme do výsledného spustitelného binárního souboru vložit obsah textového souboru pojmenovaného „ipsum.txt“. Následně k tomuto obsahu přistoupíme přes virtuální souborový systém s využitím metody FS.ReadFile. Tato metoda vrací řez bajtů, takže před tiskem provedeme převod na řetězec s využitím konverzního mechanismu string([]byte).

Celý zdrojový kód bude vypadat následovně:

package main
 
import (
        "embed"
        "fmt"
        "log"
)
 
//go:embed lorem_ipsum.txt
var f embed.FS
 
func main() {
        data, err := f.ReadFile("lorem_ipsum.txt")
        if err != nil {
                log.Fatal(err)
        }
 
        // pouziti retezce
        fmt.Println(string(data))
}

Nyní provedeme překlad projektu:

$ go build access_string.go

A následně výsledný spustitelný soubor skutečně spustíme:

$ ./access_string

Na terminálu by se mělo zobrazit následujících šest řádků:

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.

Zdrojový kód tohoto příkladu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article_AB/ac­cess_string.go.

9. Vložení rastrových dat ve formátu JPEG, export obrázku v runtime

Jak jsme se již dozvěděli v předchozím textu, je možné do výsledného binárního souboru vkládat i poměrně rozsáhlá data. Může se například jednat o rastrové obrázky. Ukažme si tedy program, který ve svém spustitelném souboru obsahuje rastrový obrázek uložený ve formátu JPEG. Po spuštění tohoto programu je obrázek exportován na disk (ovšem stejně tak by mohl být poslán jako odpověď na HTTP dotaz atd.):

package main
 
import (
        "embed"
        "log"
        "os"
)
 
//go:embed npe.jpg
var f embed.FS
 
func main() {
        data, err := f.ReadFile("npe.jpg")
        if err != nil {
                log.Fatal(err)
        }
 
        // open output file
        fout, err := os.Create("npe2.jpg")
        if err != nil {
                log.Fatal(err)
        }
        // close fo on exit and check for its returned error
        defer func() {
                err := fout.Close()
                if err != nil {
                        log.Fatal(err)
                }
        }()
 
        fout.Write(data)
}

Po spuštění tohoto programu by se měl v pracovním adresáři objevit nový soubor nazvaný „npe2.jpg“, který vypadá následovně:

Obrázek 1: Obsah souboru vytvořeného předchozím příkladem.

Zdrojový kód tohoto příkladu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article_AB/ac­cess_binary.go.

10. Jak lze do virtuálního souborového systému přidat větší množství souborů?

Samozřejmě nám nic nebrání ve vložení většího množství souborů, které budou po překladu aplikace dostupné přes virtuální souborový systém. Jedna z nabízených možností spočívá v explicitním uvedení všech vkládaných souborů, přičemž každý soubor bude specifikován jedním strukturovaným komentářem //go:embed. V praxi to může vypadat následovně:

package main
 
import (
        "embed"
        "fmt"
        "log"
)
 
//go:embed hello.txt
//go:embed lorem_ipsum.txt
var f embed.FS
 
func main() {
        data, err := f.ReadFile("lorem_ipsum.txt")
        if err != nil {
                log.Fatal(err)
        }
 
        // pouziti retezce
        fmt.Println(string(data))
}

Zdrojový kód tohoto příkladu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article_AB/mo­re_strings1.go.

Překladač programovacího jazyka Go ovšem rozpoznává i žolíkové znaky (globs), takže nám nic nebrání v tom, abychom do virtuálního souborového systému vložili například všechny soubory s koncovkou „.txt“:

package main
 
import (
        "embed"
        "fmt"
        "log"
)
 
//go:embed *.txt
var f embed.FS
 
func main() {
        data, err := f.ReadFile("lorem_ipsum.txt")
        if err != nil {
                log.Fatal(err)
        }
 
        // pouziti retezce
        fmt.Println(string(data))
}
Poznámka: obě předchozí možnosti je ovšem možné v případě potřeby zkombinovat.

Zdrojový kód tohoto příkladu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article_AB/mo­re_strings2.go.

11. Získání seznamu všech souborů vložených do vybraného virtuálního adresáře

Rozhraní, přes které se přistupuje k virtuálnímu souborovému systému, obsahuje i metodu nazvanou ReadDir, která slouží k přečtení obsahu vybraného virtuálního adresáře. V našem konkrétním příkladu vložíme do virtuálního souborového systému několik textových souborů (s využitím globu „*.txt“) a v runtime přečteme jejich seznam právě metodou ReadDir, které předáme aktuální adresář reprezentovaný tečkou:

package main
 
import (
        "embed"
        "fmt"
        "log"
)
 
//go:embed *.txt
var f embed.FS
 
func main() {
        entries, err := f.ReadDir(".")
        if err != nil {
                log.Fatal(err)
        }
 
        for _, entry := range entries {
                fmt.Printf("%-25s  %s\n", entry.Name(), entry.Type())
        }
}

Po překladu a spuštění tohoto příkladu by se na terminál měly vypsat následující řádky:

$ go run dir.go
 
hello.txt                  ----------
lorem_ipsum.txt            ----------
Poznámka: povšimněte si, že metoda entry.Type pro jednu strukturu vrácenou metodou emded.FS.ReadDir, vrátí pouze „----------“. Jak uvidíme dále, bude typ odlišný pro podadresáře atd.

Zdrojový kód tohoto příkladu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article_AB/dir.go.

12. Větší množství adresářů ve virtuálním souborovém systému

Ve virtuálním souborovém systému můžeme mít uloženou i adresářovou strukturu, což se provádí například následovně (opět zde tedy používáme globy):

//go:embed adresář1/*
//go:embed adresář2/*
var f embed.FS

Podívejme se nyní na konkrétní případ ve chvíli, kdy existuje dvojice adresářů a a b s vkládanými soubory:

a
├── A1.txt
└── A2.txt
b
├── B1.txt
├── B2.txt
└── B3.txt

Všechny textové soubory z obou adresářů vložíme do výsledného spustitelného binárního souboru (v době překladu – compile time) a v čase běhu (runtime) si vypíšeme obsah kořenového virtuálního adresáře:

package main
 
import (
        "embed"
        "fmt"
        "log"
)
 
//go:embed a/*
//go:embed b/*
var f embed.FS
 
func main() {
        entries, err := f.ReadDir(".")
        if err != nil {
                log.Fatal(err)
        }
 
        for _, entry := range entries {
                fmt.Printf("%-25s  %s\n", entry.Name(), entry.Type())
        }
}

Výsledek by měl v tomto případě vypadat následovně:

a                          d---------
b                          d---------
Poznámka: nyní je tedy typ souborů nastaven na „adresář“.

Zdrojový kód tohoto příkladu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article_AB/dir2.go.

Samozřejmě nám nic nebrání v tom, abychom si vypsali obsah konkrétních virtuálních podadresářů:

package main
 
import (
        "embed"
        "fmt"
        "log"
)
 
//go:embed a/*
//go:embed b/*
var f embed.FS
 
func main() {
        entries, err := f.ReadDir("a")
        if err != nil {
                log.Fatal(err)
        }
 
        for _, entry := range entries {
                fmt.Printf("%-25s  %s\n", entry.Name(), entry.Type())
        }
 
        fmt.Println("*************************************")
 
        entries, err = f.ReadDir("b")
        if err != nil {
                log.Fatal(err)
        }
 
        for _, entry := range entries {
                fmt.Printf("%-25s  %s\n", entry.Name(), entry.Type())
        }
}

Tentokrát budou výsledky pochopitelně odlišné:

A1.txt                     ----------
A2.txt                     ----------
*************************************
B1.txt                     ----------
B2.txt                     ----------
B3.txt                     ----------

Zdrojový kód tohoto příkladu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article_AB/dir3.go.

bitcoin_skoleni

13. Závěr

Balíček embed, který byl do ekosystému programovacího jazyka Go přidán ve verzi 1.16, může být pro některé typy aplikací velmi užitečný, protože zjednodušuje instalaci (která tak mnohdy vyžaduje pouze zkopírování jediného souboru) a navíc zmenšuje pravděpodobnost chyb, které s instalacemi či reinstalacemi souvisí – tedy chybějící soubory, soubory s jinými než očekávanými přístupovými právy, soubory ze starší verze aplikace, které nebyly při reinstalaci/upgradu přepsány atd. Nasazení takové aplikace je jednodušší i v „kontejnerizovaném IT světě“ atd. Přitom díky balíčku embed je vkládání dat do výsledných souborů nezávislé na použité architektuře ani na operačním systému.

14. Repositář s demonstračními příklady

Zdrojové kódy všech dnes použitých demonstračních příkladů naprogramovaných v jazyku Go byly uloženy do Git repositáře, který je dostupný na adrese https://github.com/tisnik/go-root. V případě, že nebudete chtít klonovat celý repositář, můžete namísto toho použít odkazy na jednotlivé demonstrační příklady, které naleznete v následující tabulce:

# Příklad/soubor Stručný popis Cesta
1 embed_string0.go vložení jednořádkového řetězce do výsledného spustitelného souboru (nekorektní varianta) https://github.com/tisnik/go-root/blob/master/article_AB/em­bed_string0.go
2 embed_string1.go vložení jednořádkového řetězce do výsledného spustitelného souboru (nekorektní varianta) https://github.com/tisnik/go-root/blob/master/article_AB/em­bed_string1.go
3 embed_string2.go vložení jednořádkového řetězce do výsledného spustitelného souboru (korektní varianta) https://github.com/tisnik/go-root/blob/master/article_AB/em­bed_string2.go
4 embed_string3.go vložení víceřádkového řetězce do výsledného spustitelného souboru https://github.com/tisnik/go-root/blob/master/article_AB/em­bed_string3.go
       
5 embed_binary1.go vložení binárních dat do výsledného spustitelného souboru https://github.com/tisnik/go-root/blob/master/article_AB/em­bed_binary1.go
6 embed_binary2.go vložení binárních dat do výsledného spustitelného souboru https://github.com/tisnik/go-root/blob/master/article_AB/em­bed_binary2.go
       
7 embed_other_data.go pokus o vložení dat odlišného typu https://github.com/tisnik/go-root/blob/master/article_AB/em­bed_other_data.go
       
8 access_string.go přístup k původnímu řetězci přes virtuální souborový systém https://github.com/tisnik/go-root/blob/master/article_AB/ac­cess_string.go
9 access_binary.go přístup k binárním datům přes virtuální souborový systém https://github.com/tisnik/go-root/blob/master/article_AB/ac­cess_binary.go
       
10 more_strings1.go větší množství řetězců, přístup k nim přes virtuální souborový systém https://github.com/tisnik/go-root/blob/master/article_AB/mo­re_strings1.go
11 more_strings2.go větší množství řetězců, přístup k nim přes virtuální souborový systém https://github.com/tisnik/go-root/blob/master/article_AB/mo­re_strings2.go
       
12 dir.go výpis všech dat, která jsou vložena do spustitelného souboru a dostupná přes virtuální souborový systém https://github.com/tisnik/go-root/blob/master/article_AB/dir.go
13 dir2.go výpis všech dat v adresáři, která jsou vložena do spustitelného souboru a dostupná přes virtuální souborový systém https://github.com/tisnik/go-root/blob/master/article_AB/dir2.go
14 dir3.go výpis všech dat v adresářích, která jsou vložena do spustitelného souboru a dostupná přes virtuální souborový systém https://github.com/tisnik/go-root/blob/master/article_AB/dir3.go

15. Odkazy na Internetu

  1. Popis balíčku embed
    https://pkg.go.dev/embed
  2. How to Use go:embed in Go
    https://blog.jetbrains.com/go/2021/06/09/how-to-use-go-embed-in-go-1–16/
  3. How to embed files into Go binaries
    https://stackoverflow.com/qu­estions/17796043/how-to-embed-files-into-go-binaries
  4. Include binary file with GNU ld linker script
    https://stackoverflow.com/qu­estions/327609/include-binary-file-with-gnu-ld-linker-script
  5. Executable and Linkable Format
    https://en.wikipedia.org/wi­ki/Executable_and_Linkable_For­mat
  6. Executable and Linkable Format 101 – Part 1 Sections and Segments
    https://intezer.com/blog/re­search/executable-linkable-format-101-part1-sections-segments/
  7. appending data to an exe
    https://stackoverflow.com/qu­estions/5795446/appending-data-to-an-exe
  8. Embedding resources in executable using GCC
    https://stackoverflow.com/qu­estions/4158900/embedding-resources-in-executable-using-gcc
  9. Go 1.18 Release Notes
    https://golang.org/doc/go1.18
  10. Go 1.17 Release Notes
    https://golang.org/doc/go1.17
  11. Go 1.16 Release Notes
    https://golang.org/doc/go1.16
  12. Go 1.15 Release Notes
    https://golang.org/doc/go1.15
  13. Go 1.14 Release Notes
    https://golang.org/doc/go1.14
  14. Go 1.13 Release Notes
    https://golang.org/doc/go1.13
  15. Go 1.12 Release Notes
    https://golang.org/doc/go1.12
  16. Go 1.11 Release Notes
    https://golang.org/doc/go1.11
  17. Go 1.10 Release Notes
    https://golang.org/doc/go1.10
  18. Go 1.9 Release Notes
    https://golang.org/doc/go1.9
  19. Go 1.8 Release Notes
    https://golang.org/doc/go1.8

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.