Statik kaynakları bir Go programında toplamanın en iyi yolu nedir? [kapalı]


100

Go'da, bir geliştiricinin makinesinde, uygulamalarında / web hizmetlerinde hata ayıklamaya yardımcı olacak bir araç olarak kullanılması amaçlanan küçük bir web uygulaması üzerinde çalışıyorum. Programın arayüzü, yalnızca HTML'yi değil, bazı JavaScript (işlevsellik için), resimler ve CSS (stil için) içeren bir web sayfasıdır. Bu uygulamayı açık kaynaklı hale getirmeyi planlıyorum, bu nedenle kullanıcılar bir Makefile çalıştırabilir ve tüm kaynaklar gitmeleri gereken yere gider. Bununla birlikte, bir yürütülebilir dosyayı olabildiğince az dosya / bağımlılıkla dağıtabilmeyi de isterim. HTML / CSS / JS'yi yürütülebilir dosya ile paketlemenin iyi bir yolu var mı, böylece kullanıcıların yalnızca bir dosya indirmesi ve endişelenmesi gerekiyor mu?


Şu anda, uygulamamda statik bir dosya sunmak biraz şuna benziyor:

// called via http.ListenAndServe
func switchboard(w http.ResponseWriter, r *http.Request) {

    // snipped dynamic routing...

    // look for static resource
    uri := r.URL.RequestURI()
    if fp, err := os.Open("static" + uri); err == nil {
        defer fp.Close()
        staticHandler(w, r, fp)
        return
    }

    // snipped blackhole route
}

Bu yüzden oldukça basit: İstenen dosya statik dizinimde mevcutsa, işleyiciyi çağırın, bu dosya basitçe dosyayı açar ve Content-Typesunmadan önce bir iyi ayarlamaya çalışır . Benim düşüncem, bunun gerçek dosya sistemine dayanması için hiçbir neden olmadığıydı: derlenmiş kaynaklar varsa, bunları istek URI'sine göre indeksleyebilir ve onlara bu şekilde hizmet edebilirdim.

Bunu yapmanın iyi bir yolu yoksa veya bunu yapmaya çalışarak yanlış ağaca havlıyorsam bana haber ver. Son kullanıcının yönetmek için mümkün olduğunca az dosyayı beğeneceğini düşündüm.

Şundan daha uygun etiketler varsa , lütfen çekinmeden ekleyin veya bana bildirin.



Aslında bugün tamamen aynı soruyu düşündüm. Ben keşfetmek olabileceğini çözüm kullanmaktır go generatedosyaları dönüştürmek için (benim kaynak kodu ile paketlenmiş) küçük bir komut satırı yardımcı programı ile []bytenasıl benzer kod değişkenler olarak gömülü dilimler, stringeröyle (bkz blog.golang.org / oluşturmak ).
Ralph

Yanıtlar:


76

Go-bindata paketi ilgilendiğiniz şey gibi görünüyor.

https://github.com/go-bindata/go-bindata

Herhangi bir statik dosyayı, kodunuza gömülebilecek bir işlev çağrısına dönüştürmenize izin verir ve çağrıldığında dosya içeriğinin bir bayt dilimini döndürür.


8
Bunu desteklemek benim durumumda garip bir şekilde kendi kendine hizmet ediyor gibi görünüyor, ancak yine de yapacağım: p Yine de kayıt için, bu bir paket değil, bir komut satırı aracıdır.
jimt

Kayıt için, projemde izlediğim yol bu. Bir noktada @jimt, işleri daha kullanıcı dostu hale getirmek için bazı yeni özellikler sundu, ancak artık ihtiyacım olan ayrıntı düzeyini sağlamadı, bu yüzden daha az özelliği olan ancak kendi kullanım alanım için tasarlanmış kendi aracımı yazdım (bu aracı bir tür yapım sürecine giriş): github.com/jimmysawczuk/go-binary
Jimmy Sawczuk

37

Metin Dosyalarını Gömme

Metin dosyalarından bahsediyorsak, kolayca kaynak kodun içine gömülebilirler. Geriye dönük tırnak işaretlerini şu şekilde ifade etmek için kullanın string:

const html = `
<html>
<body>Example embedded HTML content.</body>
</html>
`

// Sending it:
w.Write([]byte(html))  // w is an io.Writer

Optimizasyon ipucu:

Çoğu zaman kaynağı yalnızca bir'e yazmanız gerekeceğinden io.Writer, bir []bytedönüşümün sonucunu da saklayabilirsiniz :

var html = []byte(`
<html><body>Example...</body></html>
`)

// Sending it:
w.Write(html)  // w is an io.Writer

Dikkat etmeniz gereken tek şey, ham dize değişmezlerinin geri tırnak karakterini (`) içeremeyeceğidir. Ham dize değişmezleri diziler içeremez (yorumlanan dize değişmez değerlerinin aksine), bu nedenle gömmek istediğiniz metin ters tırnak içeriyorsa, ham dize değişmezini kırmanız ve bu örnekte olduğu gibi geri tırnakları yorumlanmış dize değişmezleri olarak birleştirmeniz gerekir:

var html = `<p>This is a back quote followed by a dot: ` + "`" + `.</p>`

Bu birleştirmeler derleyici tarafından yürütüleceğinden performans etkilenmez.

İkili Dosyaları Gömme

Bayt dilimi olarak saklama

İkili dosyalar (ör. Görüntüler) için en kompakt (sonuçta ortaya çıkan yerel ikili ile ilgili) ve en verimli, dosyanın içeriğinin []bytekaynak kodunuzda olduğu gibi olması olacaktır. Bu, go-bindata gibi 3. taraf araçlar / kitaplıklar tarafından oluşturulabilir .

Bunun için bir 3. taraf kitaplığı kullanmak istemiyorsanız, işte bir ikili dosyayı okuyan basit bir kod parçacığı ve dosyanın []bytetam içeriğiyle başlatılacak bir tür değişkeni bildiren Go kaynak kodu çıktı :

imgdata, err := ioutil.ReadFile("someimage.png")
if err != nil {
    panic(err)
}

fmt.Print("var imgdata = []byte{")
for i, v := range imgdata {
    if i > 0 {
        fmt.Print(", ")
    }
    fmt.Print(v)
}
fmt.Println("}")

Dosya 0'dan 16'ya kadar bayt içerecekse örnek çıktı ( Go Playground'da deneyin ):

var imgdata = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}

Base64 olarak saklama string

Dosya "çok büyük" değilse (çoğu görüntü / simge uygunsa), başka geçerli seçenekler de vardır. Dosyanın içeriğini Base64'e dönüştürebilir stringve bunu kaynak kodunuzda saklayabilirsiniz. Uygulama başlangıcında ( func init()) veya gerektiğinde, orijinal []byteiçeriğe dönüştürebilirsiniz. Go, encoding/base64pakette Base64 kodlaması için güzel bir desteğe sahiptir .

Bir (ikili) dosyayı base64'e dönüştürmek stringşu kadar basittir:

data, err := ioutil.ReadFile("someimage.png")
if err != nil {
    panic(err)
}
fmt.Println(base64.StdEncoding.EncodeToString(data))

Sonuç base64 dizesini kaynak kodunuzda saklayın, örneğin const.

Kodunu çözmek sadece bir işlev çağrısıdır:

const imgBase64 = "<insert base64 string here>"

data, err := base64.StdEncoding.DecodeString(imgBase64) // data is of type []byte

Alıntılandığı gibi saklanıyor string

Base64 olarak depolamaktan daha verimli, ancak kaynak kodda daha uzun sürebilir , ikili verilerin alıntılanan dize hazır bilgisini depolamaktır . Herhangi bir dizgenin alıntılanmış biçimini strconv.Quote()işlevi kullanarak elde edebiliriz :

data, err := ioutil.ReadFile("someimage.png")
if err != nil {
    panic(err)
}
fmt.Println(strconv.Quote(string(data))

0'dan 64'e kadar değerler içeren ikili veriler için çıktı şu şekilde görünür ( Go Playground'da deneyin ):

"\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?"

( strconv.Quote()Bir tırnak işareti eklediğini ve başına eklediğini unutmayın .)

Bu tırnak içine alınmış dizeyi kaynak kodunuzda doğrudan kullanabilirsiniz, örneğin:

const imgdata = "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?"

Kullanıma hazırdır, kodunun çözülmesine gerek yoktur; alıntı kaldırma işlemi derleme zamanında Go derleyicisi tarafından yapılır.

İhtiyaç duymanız durumunda bir bayt dilimi olarak da saklayabilirsiniz:

var imgdata = []byte("\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?")

bir shdosyayı bir go yürütülebilir dosyaya bağlamanın herhangi bir yolu var mı?
Kasun Siyambalapitiya

Sanırım veriler, "bayt dilimi olarak depolama" bölümünün altındaki ilk kod parçacığındaki imgdata olmalıdır.
mantıksal x 2

1
@deusexmachina Haklısın, düzelttin. Oyun parkındaki kod zaten doğruydu.
icza

2

ayrıca bazı egzotik yollar da var - GoLang projeleri oluşturmak için maven eklentisini kullanıyorum ve kaynaklara ikili bloklar ve metin dosyaları yerleştirmek için JCP ön işlemcisini kullanmaya izin veriyor . Durumda, kod aşağıdaki satıra benziyor ( ve bazı örnekler burada bulunabilir )

var imageArray = []uint8{/*$binfile("./image.png","uint8[]")$*/}

@ shYukarıdaki gibi bir veya çalıştırılabilir dosya içeren bir dizini bağlamak mümkün mü
Kasun Siyambalapitiya

@KasunSiyambalapitiya Bir dizini bağla? Bir shdosya bağlamak mı? Ne demek istediğinden emin değilim. Bir dizindeki her şeyin gömülü olmasını istiyorsanız, bu benim yaptığım bir şey go-bindata. Örneğin, //go:generate $GOPATH/bin/go-bindata -prefix=data/ -pkg=$GOPACKAGE data/(oluşturulmamış) bir go dosyası go generate ./...koyarsam, paketin dizininde go-bindata çalıştıracak ve her şeyi bir veri alt dizinine gömer, ancak 'data /' öneki kaldırılacaktır.
Mark

1

go-bindataBaşka bir cevapta bahsedilen popüler bir alternatif olarak , mjibson / esc ayrıca rastgele dosyaları da gömer, ancak dizin ağaçlarını özellikle uygun bir şekilde işler.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.