从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。 这个方法有几个注意事项:
- 没有保证,这将在所有去编译器工作。 虽然这与9 gc编译器一起工作,但它依赖于官方规范中没有提到的“实现细节”。 你甚至不能保证,这将适用于所有架构或不能在gc中进行更改。 换句话说,这是一个坏主意。
- 那个string是可变的! 如果您在该缓冲区上进行任何调用, 它将更改该string。 要特别小心。
我的build议是坚持官方的方法。 做一个副本并不昂贵,这是不值得的不安全的罪恶。 如果string太大而无法复制,则不应将其设置为string。
迄今为止的答案并没有解决问题的“整个stream”部分。 我认为这样做的好方法是ioutil.ReadAll
。 用你的名为rc
的io.ReaderCloser
,我会写,
if b, err := ioutil.ReadAll(rc); err == nil { return string(b) } ...
最有效的方法是始终使用[]byte
而不是string
。
如果需要打印从io.ReadCloser
接收到的io.ReadCloser
, fmt
软件包可以处理[]byte
,但效率不高,因为fmt
实现将在内部将[]byte
转换为string
。 为了避免这种转换,你可以实现type ByteSlice []byte
的types的fmt.Formatter
接口。
我喜欢bytes.Buffer结构。 我看到它有ReadFrom和String方法。 我用[]字节而不是io.Reader。