从io.Reader到Go中的string

我有一个io.ReadCloser对象(从一个http.Response对象)。

将整个stream转换为string对象的最有效方法是什么?

简单的答案是它不会有效,因为转换为string需要完成字节数组的拷贝。 这是正确的(非高效的)方法来做你想做的事情:

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

这个副本是作为一个保护机制完成的。 string是不可改变的。 如果可以将[]字节转换为string,则可以更改string的内容。 但是,go允许您禁用使用不安全软件包的types安全机制。 使用不安全的软件包需要您自担风险。 希望这个名字是一个足够好的警告。 以下是我将如何使用不安全:

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

在那里,你现在已经有效地将你的字节数组转换为一个string。 真的,所有这一切都是欺骗types系统调用它一个string。 这个方法有几个注意事项:

  1. 没有保证,这将在所有去编译器工作。 虽然这与9 gc编译器一起工作,但它依赖于官方规范中没有提到的“实现细节”。 你甚至不能保证,这将适用于所有架构或不能在gc中进行更改。 换句话说,这是一个坏主意。
  2. 那个string是可变的! 如果您在该缓冲区上进行任何调用, 它将更改该string。 要特别小心。

我的build议是坚持官方的方法。 做一个副本并不昂贵,这是不值得的不安全的罪恶。 如果string太大而无法复制,则不应将其设置为string。

迄今为止的答案并没有解决问题的“整个stream”部分。 我认为这样做的好方法是ioutil.ReadAll 。 用你的名为rcio.ReaderCloser ,我会写,

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

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

如果需要打印从io.ReadCloser接收到的io.ReadCloserfmt软件包可以处理[]byte ,但效率不高,因为fmt实现将在内部将[]byte转换为string 。 为了避免这种转换,你可以实现type ByteSlice []byte的types的fmt.Formatter接口。

我喜欢bytes.Buffer结构。 我看到它有ReadFrom和String方法。 我用[]字节而不是io.Reader。