簡體   English   中英

從 io.Reader 到 Go 中的字符串

[英]From io.Reader to string in Go

我有一個io.ReadCloser對象(來自http.Response對象)。

將整個流轉換為string對象的最有效方法是什么?

編輯:

從 1.10 開始,strings.Builder 就存在了。 例子:

buf := new(strings.Builder)
n, err := io.Copy(buf, r)
// check errors
fmt.Println(buf.String())

以下過時信息

簡短的回答是它效率不高,因為轉換為字符串需要對字節數組進行完整的復制。 這是做你想做的正確(非有效)的方法:

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

此副本是作為保護機制完成的。 字符串是不可變的。 如果可以將 []byte 轉換為字符串,則可以更改字符串的內容。 但是,go 允許您使用 unsafe 包禁用類型安全機制。 使用 unsafe 包的風險由您自己承擔。 希望這個名字本身就是一個足夠好的警告。 這是我將如何使用 unsafe 來做到這一點:

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

好了,您現在已經有效地將字節數組轉換為字符串。 實際上,所有這些都是欺騙類型系統將其稱為字符串。 這種方法有幾個注意事項:

  1. 不能保證這將適用於所有 go 編譯器。 雖然這適用於 plan-9 gc 編譯器,但它依賴於官方規范中未提及的“實現細節”。 您甚至不能保證這將適用於所有架構或不會在 gc 中更改。 換句話說,這是一個壞主意。
  2. 該字符串是可變的! 如果您對該緩沖區進行任何調用,它將更改字符串。 要非常小心。

我的建議是堅持官方的方法。 做一個副本並不那么昂貴,也不值得不安全的罪惡。 如果字符串太大而無法復制,則不應將其制作成字符串。

到目前為止,答案還沒有解決問題的“整個流”部分。 我認為這樣做的好方法是ioutil.ReadAll 使用名為rcio.ReaderCloser ,我會寫,

去>= v1.16

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

去 <= v1.15

if b, err := ioutil.ReadAll(rc); err == nil {
    return string(b)
} ...
data, _ := ioutil.ReadAll(response.Body)
fmt.Println(string(data))

最有效的方法是始終使用[]byte而不是string

如果您需要打印從io.ReadCloser接收到的io.ReadCloserfmt包可以處理[]byte ,但效率不高,因為fmt實現會在內部將[]byte轉換為string 為了避免這種轉換,您可以為類似type ByteSlice []byte的類型實現fmt.Formatter接口。

func copyToString(r io.Reader) (res string, err error) {
    var sb strings.Builder
    if _, err = io.Copy(&sb, r); err == nil {
        res = sb.String()
    }
    return
}
var b bytes.Buffer
b.ReadFrom(r)

// b.String()

我喜歡bytes.Buffer結構。 我看到它有ReadFromString方法。 我已經將它與 []byte 一起使用,但沒有與 io.Reader 一起使用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM