Go प्रोग्राम में स्थिर संसाधनों को बंडल करने का सबसे अच्छा तरीका क्या है? [बन्द है]


100

मैं गो में एक छोटे से वेब एप्लिकेशन पर काम कर रहा हूं जिसका उपयोग किसी डेवलपर की मशीन पर एक टूल के रूप में उनके अनुप्रयोगों / वेब सेवाओं को डिबग करने में मदद करने के लिए किया जाता है। कार्यक्रम का इंटरफ़ेस एक वेब पेज है जिसमें न केवल HTML, बल्कि कुछ जावास्क्रिप्ट (कार्यक्षमता के लिए), चित्र और CSS (स्टाइल के लिए) शामिल हैं। मैं इस एप्लिकेशन को ओपन सोर्स करने की योजना बना रहा हूं, इसलिए उपयोगकर्ताओं को बस मेकफाइल चलाने में सक्षम होना चाहिए और वे सभी संसाधन जाएंगे जहां उन्हें जाने की आवश्यकता है। हालाँकि, मैं यह भी चाहूंगा कि बस एक निष्पादन योग्य को कुछ फाइलों / आश्रितों के साथ वितरित किया जा सके। क्या निष्पादन योग्य के साथ HTML / CSS / JS को बंडल करने का एक अच्छा तरीका है, ताकि उपयोगकर्ताओं को केवल एक फ़ाइल के बारे में डाउनलोड और चिंता करनी पड़े?


अभी, मेरे ऐप में, एक स्टैटिक फ़ाइल परोसना कुछ इस तरह दिखता है:

// 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
}

तो यह बहुत आसान है: यदि अनुरोधित फ़ाइल मेरे स्थिर निर्देशिका में मौजूद है, तो हैंडलर को लागू करें, जो बस फ़ाइल को खोलता है और Content-Typeसेवा करने से पहले एक अच्छा सेट करने की कोशिश करता है । मेरा विचार यह था कि वास्तविक फाइलसिस्टम पर आधारित होने की कोई आवश्यकता नहीं है: यदि संकलित संसाधन थे, तो मैं उन्हें केवल अनुरोध URI द्वारा अनुक्रमित कर सकता हूं और उन्हें इस तरह से सेवा कर सकता हूं।

यदि ऐसा करने का कोई अच्छा तरीका नहीं है, या मैं ऐसा करने की कोशिश करके गलत पेड़ को काट रहा हूं, तो मुझे बताएं। मुझे लगा कि एंड-यूज़र कुछ फ़ाइलों को प्रबंधित करने के लिए संभव होगा।

यदि से अधिक उपयुक्त टैग हैं , कृपया उन्हें जोड़ने के लिए स्वतंत्र महसूस करें या मुझे बताएं।



मैंने वास्तव में आज ठीक उसी प्रश्न के बारे में सोचा था। जो समाधान मैं खोज सकता हूं वह है go generateएक छोटी कमांड-लाइन उपयोगिता (मेरे स्रोत कोड के साथ पैक) का उपयोग करके फ़ाइलों को []byteस्लाइस में परिवर्तित करने के लिए जो कोड में चर के रूप में एम्बेडेड हैं, stringerयह कैसे करता है (देखें blog.golang.org / उत्पन्न )।
राल्फ

जवाबों:


76

गो-बिंदता पैकेज ऐसा लग रहा है कि हो सकता है कि आपकी रूचि हो।

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

यह आपको किसी भी स्थिर फ़ाइल को एक फ़ंक्शन कॉल में परिवर्तित करने की अनुमति देगा जो आपके कोड में एम्बेड किया जा सकता है और कॉल किए जाने पर फ़ाइल सामग्री का एक बाइट टुकड़ा वापस कर देगा।


8
यह देखते हुए कि यह मेरे मामले में अजीब तरह से सेल्फ-सर्विंग है, लेकिन मैं इसे वैसे भी करूँगा: p रिकॉर्ड के लिए हालांकि, यह एक पैकेज नहीं है, बल्कि एक कमांड-लाइन टूल है।
jimt

सिर्फ रिकॉर्ड के लिए, यह वह रास्ता है जिसे मैंने अपने प्रोजेक्ट के साथ लिया था। कुछ बिंदु पर @jimt ने चीजों को अधिक उपयोगकर्ता-अनुकूल बनाने के लिए कुछ नई सुविधाएँ पेश कीं, लेकिन अब मुझे जिस ग्रैन्युलैरिटी की आवश्यकता नहीं थी, इसलिए मैंने अपना स्वयं का टूल लिखा है जिसमें कम सुविधाएँ हैं लेकिन मेरे usecase के लिए डिज़ाइन किया गया है (मैं इस टूल को एक प्रकार के रूप में उपयोग करता हूं) निर्माण प्रक्रिया के लिए प्रस्तावना): github.com/jimmysawczuk/go-binary
जिम्मी सवाकुक

37

पाठ फ़ाइलों को एम्बेड करना

यदि हम पाठ फ़ाइलों के बारे में बात कर रहे हैं, तो वे आसानी से स्रोत कोड में ही एम्बेड किए जा सकते हैं। stringइस तरह शाब्दिक घोषित करने के लिए बस पीछे के उद्धरणों का उपयोग करें:

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

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

अनुकूलन टिप:

चूंकि अधिकांश समय आपको केवल संसाधन को लिखने की आवश्यकता होगी io.Writer, इसलिए आप []byteरूपांतरण का परिणाम भी संग्रहीत कर सकते हैं :

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

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

केवल एक चीज जिसके बारे में आपको सावधान रहना है, वह यह है कि कच्चे स्ट्रिंग शाब्दिकों में पीछे की बोली वर्ण (`) नहीं हो सकती है। कच्चे स्ट्रिंग शाब्दिकों में अनुक्रमणिका (व्याख्या की गई स्ट्रिंग शाब्दिक के विपरीत) नहीं हो सकती है, इसलिए यदि आप जिस पाठ को एम्बेड करना चाहते हैं, उसमें वापस उद्धरण शामिल हैं, तो आपको कच्चे स्ट्रिंग शाब्दिक और संक्षिप्त उद्धरणों को व्याख्यायित स्ट्रिंग शाब्दिकों के रूप में तोड़ना होगा, जैसे कि इस उदाहरण में:

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

प्रदर्शन प्रभावित नहीं होता है, क्योंकि इन संघनन को संकलक द्वारा निष्पादित किया जाएगा।

बाइनरी फाइलें एम्बेड करना

बाइट स्लाइस के रूप में भंडारण

बाइनरी फ़ाइलों (उदाहरण के लिए चित्र) के लिए सबसे कॉम्पैक्ट (परिणामी मूल बाइनरी के बारे में) और सबसे अधिक कुशल []byteआपके स्रोत कोड में फ़ाइल की सामग्री होना चाहिए । इसे गो-बिंदता जैसे 3 पार्टी टोसे / लाइब्रेरी द्वारा उत्पन्न किया जा सकता है ।

यदि आप इसके लिए एक 3 पार्टी लाइब्रेरी का उपयोग नहीं करना चाहते हैं, तो यहां एक सरल कोड स्निपेट है जो एक बाइनरी फ़ाइल को पढ़ता है, और गो स्रोत कोड को आउटपुट करता है जो कि एक प्रकार का चर घोषित करता है []byteजिसे फ़ाइल की सटीक सामग्री के साथ आरंभ किया जाएगा:

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("}")

उदाहरण आउटपुट यदि फ़ाइल में 0 से 16 तक बाइट्स होंगे (इसे Go Playground पर आज़माएँ ):

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

आधार के रूप में भंडारण string

यदि फ़ाइल "बहुत बड़ी" नहीं है (अधिकांश चित्र / आइकन योग्य हैं), तो अन्य व्यवहार्य विकल्प भी हैं। आप फ़ाइल की सामग्री को बेस 64 में रूपांतरित कर सकते हैं stringऔर अपने स्रोत कोड में संग्रहीत कर सकते हैं। एप्लिकेशन स्टार्टअप पर ( func init()) या जब आवश्यक हो, आप इसे मूल []byteसामग्री को डिकोड कर सकते हैं । encoding/base64पैकेज में बेस 64 एनकोडिंग के लिए गो का अच्छा समर्थन है ।

एक (बाइनरी) फ़ाइल को बेस 64 stringमें परिवर्तित करना उतना ही सरल है:

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

अपने स्रोत कोड में परिणाम बेस 64 स्ट्रिंग को स्टोर करें, जैसे कि ए const

डिकोड करना यह केवल एक फ़ंक्शन कॉल है:

const imgBase64 = "<insert base64 string here>"

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

उद्धृत के रूप में भंडारण string

बेस 64 के रूप में संग्रहीत करने की तुलना में अधिक कुशल, लेकिन स्रोत कोड में लंबे समय तक हो सकता है बाइनरी डेटा के उद्धृत स्ट्रिंग शाब्दिक संग्रहित कर रहा है । हम strconv.Quote()फ़ंक्शन का उपयोग करके किसी भी स्ट्रिंग के उद्धृत रूप को प्राप्त कर सकते हैं :

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

0 से 64 तक के बाइनरी डेटा के लिए यह है कि आउटपुट कैसा लगेगा (इसे गो प्लेग्राउंड पर आज़माएं ):

"\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()इसके लिए एक उद्धरण चिह्न संलग्न और प्रस्तुत करता है।)

आप सीधे अपने स्रोत कोड में इस उद्धृत स्ट्रिंग का उपयोग कर सकते हैं, उदाहरण के लिए:

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:;<=>?"

यह उपयोग करने के लिए तैयार है, इसे डिकोड करने की आवश्यकता नहीं है; संकलन समय पर, गो संकलक द्वारा किया जाता है।

आप इसे बाइट स्लाइस के रूप में भी स्टोर कर सकते हैं, आपको इसकी आवश्यकता इस तरह होनी चाहिए:

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:;<=>?")

क्या किसी shफ़ाइल को किसी निष्पादन योग्य तरीके से बाँधने का कोई तरीका है ?
कसून सियामबलपिटिया

मुझे लगता है कि पहले कोड स्निपेट में "बाइट स्लाइस के रूप में भंडारण" खंड के तहत डेटा imgdata होना चाहिए।
तार्किक एक्स 2

1
@deusexmachina आप सही हैं, इसे ठीक किया। खेल के मैदान पर कोड पहले से ही सही था।
इक्जा

2

वहाँ भी कुछ विदेशी तरीका है - मैं GoLang परियोजनाओं के निर्माण के लिए मावेन प्लगइन का उपयोग करता हूं और यह बाइनरी ब्लॉक और पाठ फ़ाइलों को स्रोतों में एम्बेड करने के लिए जेसीपी प्रीप्रोसेसर का उपयोग करने की अनुमति देता है । केस कोड में सिर्फ नीचे की तरह लाइन दिखती है ( और कुछ उदाहरण यहां देखे जा सकते हैं )

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

@ यह संभव है कि एक निर्देशिका को shऊपर या किसी निष्पादन योग्य की तरह बाँध दिया जाए
कसुन सियामबलपिटिया

@KasunSiyambalapitiya एक निर्देशिका बांधें? एक shफाइल बांधें ? पक्का नहीं आपका क्या मतलब है। यदि आप चाहते हैं कि एक निर्देशिका में सब कुछ एम्बेडेड हो, तो यह कुछ ऐसा है जो मैंने किया है go-bindata। उदाहरण के लिए, अगर मैं //go:generate $GOPATH/bin/go-bindata -prefix=data/ -pkg=$GOPACKAGE data/एक (गैर-जेनरेटेड) गो फाइल go generate ./...में रखता हूं, तो पैकेज के डीआईआर में गो-बिंदता को चलाएगा, सब-डेटा में सबडाइमर को एम्बेड करेगा, लेकिन 'डेटा /' उपसर्ग को हटा दिया जाएगा।
मार्क

1

एक go-bindataअन्य उत्तर में उल्लिखित एक लोकप्रिय विकल्प के रूप में, mjibson / esc भी मनमानी फ़ाइलों को एम्बेड करता है, लेकिन विशेष रूप से आसानी से निर्देशिका पेड़ों को संभालता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.