【发布时间】:2012-03-27 11:58:37
【问题描述】:
我有一个io.ReadCloser 对象(来自http.Response 对象)。
将整个流转换为string 对象的最有效方法是什么?
【问题讨论】:
标签: go
我有一个io.ReadCloser 对象(来自http.Response 对象)。
将整个流转换为string 对象的最有效方法是什么?
【问题讨论】:
标签: go
编辑:
从 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 的方法:
buf := new(bytes.Buffer)
buf.ReadFrom(yourReader)
b := buf.Bytes()
s := *(*string)(unsafe.Pointer(&b))
我们开始了,您现在已经有效地将字节数组转换为字符串。真的,所有这些都是欺骗类型系统将其称为字符串。这种方法有几个注意事项:
我的建议是坚持官方方法。做一个副本并不那么昂贵,也不值得不安全的危害。如果字符串太大而无法进行复制,则不应将其制成字符串。
【讨论】:
strings.Builder 通过确保底层 []byte 永不泄漏,并以未来支持的方式在没有副本的情况下转换为 string 来有效地做到这一点。这在 2012 年不存在。@dimchansky 下面的解决方案自 Go 1.10 以来一直是正确的解决方案。请考虑修改!
到目前为止,答案还没有解决问题的“整个流程”部分。我认为做到这一点的好方法是ioutil.ReadAll。用你的io.ReaderCloser 命名为rc,我会写,
开始 >= v1.16
if b, err := io.ReadAll(rc); err == nil {
return string(b)
} ...
去
if b, err := ioutil.ReadAll(rc); err == nil {
return string(b)
} ...
【讨论】:
buf.ReadFrom() 也将整个流读取到 EOF。
ioutil.ReadAll() 的实现,它只是包装了bytes.Buffer 的ReadFrom。并且缓冲区的 String() 方法是一个简单的环绕转换为 string 的方法——所以这两种方法实际上是相同的!
data, _ := ioutil.ReadAll(response.Body)
fmt.Println(string(data))
【讨论】:
最有效的方法是始终使用[]byte 而不是string。
如果您需要打印从io.ReadCloser 接收的数据,fmt 包可以处理[]byte,但效率不高,因为fmt 实现将在内部将[]byte 转换为string .为了避免这种转换,您可以为type ByteSlice []byte 之类的类型实现fmt.Formatter 接口。
【讨论】:
[]byte 到string 的转换相当快,但问题是询问“最有效的方式”。目前,Go 运行时在将[]byte 转换为string 时总是会分配一个新的string。原因是编译器不知道如何判断转换后[]byte是否会被修改。这里有一些编译器优化的空间。
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 结构。我看到它有 ReadFrom 和 String 方法。我用 []byte 但不是 io.Reader。
【讨论】: