गो

2012-03-10 17 views
89

में स्ट्रिंग करने के लिए io.Reader से मेरे पास io.ReadCloser ऑब्जेक्ट है (http.Response ऑब्जेक्ट से)।गो

संपूर्ण स्ट्रीम को string ऑब्जेक्ट में परिवर्तित करने का सबसे प्रभावी तरीका क्या है?

उत्तर

123

संक्षिप्त उत्तर यह है कि यह कुशल नहीं होगा क्योंकि स्ट्रिंग में कनवर्ट करने से बाइट सरणी की पूरी प्रतिलिपि की आवश्यकता होती है। आप जो चाहते हैं उसे करने के लिए उचित (गैर-कुशल) तरीका यहां दिया गया है:

buf := new(bytes.Buffer) 
buf.ReadFrom(yourReader) 
s := buf.String() // Does a complete copy of the bytes in the buffer. 

यह प्रति सुरक्षा तंत्र के रूप में की जाती है। स्ट्रिंग्स अपरिवर्तनीय हैं। यदि आप एक [] बाइट को एक स्ट्रिंग में परिवर्तित कर सकते हैं, तो आप स्ट्रिंग की सामग्री बदल सकते हैं। हालांकि, आपको असुरक्षित पैकेज का उपयोग करके प्रकार सुरक्षा तंत्र को अक्षम करने की अनुमति देता है। अपने जोखिम पर असुरक्षित पैकेज का प्रयोग करें। उम्मीद है कि अकेले नाम एक अच्छी पर्याप्त चेतावनी है। यहाँ कैसे मैं असुरक्षित का उपयोग कर इसे करना होगा है:

buf := new(bytes.Buffer) 
buf.ReadFrom(yourReader) 
b := buf.Bytes() 
s := *(*string)(unsafe.Pointer(&b)) 

वहाँ हम चले, अब आप कुशलता से अपने बाइट सरणी एक स्ट्रिंग में बदल जाती है। असल में, यह सब टाइप सिस्टम को स्ट्रिंग कहने में चाल है। इस विधि में कुछ चेतावनी हैं:

  1. कोई गारंटी नहीं है कि यह सभी कंप्यूटर्स में काम करेगा। हालांकि यह योजना -9 जीसी कंपाइलर के साथ काम करता है, यह आधिकारिक विशिष्टता में उल्लिखित "कार्यान्वयन विवरण" पर निर्भर करता है। आप यह भी गारंटी नहीं दे सकते कि यह सभी आर्किटेक्चर पर काम करेगा या जीसी में नहीं बदला जाएगा। दूसरे शब्दों में, यह एक बुरा विचार है।
  2. वह स्ट्रिंग mutable है! यदि आप उस बफर पर कोई कॉल करते हैं तो स्ट्रिंग को बदल देगा। बहुत सावधान रहें।

मेरी सलाह आधिकारिक विधि से चिपकना है। एक प्रतिलिपि करना है कि महंगा है और यह असुरक्षित की बुराइयों के लायक नहीं है। यदि स्ट्रिंग करने के लिए स्ट्रिंग बहुत बड़ी है, तो आपको इसे स्ट्रिंग में नहीं बनाना चाहिए।

+0

धन्यवाद, यह वास्तव में एक विस्तृत उत्तर है। "अच्छा" तरीका लगभग @ सोनिया के जवाब के बराबर लगता है (चूंकि buf.String केवल आंतरिक रूप से कलाकार करता है)। – djd

+1

और यह मेरे संस्करण के साथ भी काम नहीं करता है, ऐसा लगता है कि यह पॉइंटर प्राप्त करने में सक्षम नहीं है, लेकिन बाइट्स()। Go1 का उपयोग करना। – sinni800

+0

@ sinni800 टिप के लिए धन्यवाद। मैं भूल गया कि रिटर्न रिटर्न एड्रेसेबल नहीं थे। यह अब तय है। –

0

मुझे bytes.Buffer संरचना पसंद है। मुझे लगता है कि इसमें ReadFrom और String विधियां हैं। मैंने इसे एक [] बाइट के साथ उपयोग किया है लेकिन एक io.Reader नहीं है।

4

सबसे प्रभावी तरीका के बजाय हमेशा []byte का उपयोग करना होगा।

मामले में आप io.ReadCloser से प्राप्त डेटा मुद्रित करने के लिए, fmt पैकेज []byte संभाल कर सकते हैं की जरूरत है, लेकिन यह कुशल नहीं है क्योंकि fmt कार्यान्वयन आंतरिक string को []byte परिवर्तित कर देंगे। इस रूपांतरण से बचने के लिए, आप इंटरफेस को type ByteSlice []byte जैसे प्रकार के लिए कार्यान्वित कर सकते हैं।

+0

स्ट्रिंग महंगा करने से [] बाइट रूपांतरण है? मुझे लगता है कि स्ट्रिंग ([] बाइट) वास्तव में [] बाइट की प्रतिलिपि नहीं बनाई गई थी, लेकिन सिर्फ स्लाइस तत्वों को रनों की श्रृंखला के रूप में व्याख्या की गई थी। यही कारण है कि मैंने बफर। स्ट्रिंग() http://weekly.golang.org/src/pkg/bytes/buffer.go?s=1787:1819#L37 का सुझाव दिया। मुझे लगता है कि स्ट्रिंग ([] बाइट) कहलाते समय क्या हो रहा है यह जानना अच्छा होगा। – Nate

+4

'[] बाइट' से 'स्ट्रिंग' में रूपांतरण काफी तेज़ है, लेकिन सवाल" सबसे प्रभावी तरीका "के बारे में पूछ रहा था। वर्तमान में, 'रन] टाइम' [] बाइट' को 'स्ट्रिंग' में परिवर्तित करते समय हमेशा एक नया 'स्ट्रिंग' आवंटित करेगा। इसका कारण यह है कि संकलक यह नहीं जानता कि रूपांतरण के बाद '[] बाइट' संशोधित किया जाएगा या नहीं। यहां कंपाइलर अनुकूलन के लिए कुछ जगह है। –

63

उत्तर अब तक इस प्रश्न के "संपूर्ण स्ट्रीम" हिस्से को संबोधित नहीं किया है। मुझे लगता है कि ऐसा करने का अच्छा तरीका ioutil.ReadAll है। अपने io.ReaderCloserrc नामित के साथ, मैं लिखते थे,

if b, err := ioutil.ReadAll(rc); err == nil { 
    return string(b) 
} ... 
+2

धन्यवाद, अच्छा जवाब। ऐसा लगता है कि 'buf.ReadFrom()' ईओएफ तक पूरी स्ट्रीम भी पढ़ता है। – djd

+6

कितना हास्यास्पद है: मैंने अभी 'ioutil.ReadAll()' के कार्यान्वयन को पढ़ा है और यह बस 'बाइट्स' बफर 'के' ReadFrom' को लपेटता है। और बफर की 'स्ट्रिंग()' विधि 'स्ट्रिंग' पर कास्टिंग के चारों ओर एक साधारण लपेटो है - इसलिए दो दृष्टिकोण व्यावहारिक रूप से वही हैं! – djd

+1

यह सबसे अच्छा, सबसे संक्षिप्त समाधान है। – mk12