从io.Reader到Go中的字符串

djd*_*djd 120 go

我有一个io.ReadCloser对象(来自一个http.Response对象).

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

Ste*_*erg 166

简短的回答是它不会有效,因为转换为字符串需要完成字节数组的完整副本.这是正确的(非效率)方式来做你想要的:

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

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

buf := new(bytes.Buffer)
buf.ReadFrom(yourReader)
b := buf.Bytes()
s := *(*string)(unsafe.Pointer(&b))
Run Code Online (Sandbox Code Playgroud)

我们走了,你现在已经有效地将你的字节数组转换为字符串.实际上,所有这一切都是欺骗类型系统将其称为字符串.这种方法有几点需要注意:

  1. 无法保证这将适用于所有编译器.虽然这适用于plan-9 gc编译器,但它依赖于官方规范中未提及的"实现细节".您甚至不能保证这将适用于所有体系结构或不在gc中更改.换句话说,这是一个坏主意.
  2. 那个字符串是可变的!如果您对该缓冲区进行任何调用,它将更改字符串.要非常小心.

我的建议是坚持官方方法.做一个副本不是贵,这是不值得的不安全的弊端.如果字符串太大而无法复制,则不应将其变为字符串.

  • 好吧,计算机在复制字节块方面非常快.鉴于这是一个http请求,我无法想象一种传输延迟不会比复制字节数组所需的繁琐时间大几十亿倍的情况.任何功能语言都会在这个地方复制这种不可变的东西,并且仍能快速运行. (3认同)

Son*_*nia 93

到目前为止,答案还没有解决问题的"整个流"部分.我认为这样做的好方法是ioutil.ReadAll.有了你的io.ReaderCloser名字rc,我会写,

if b, err := ioutil.ReadAll(rc); err == nil {
    return string(b)
} ...
Run Code Online (Sandbox Code Playgroud)

  • 多么有趣:我刚刚阅读了`ioutil.ReadAll()`的实现,它只是包装`bytes.Buffer`的`ReadFrom`.缓冲区的`String()`方法是一个简单的包装转换为`string` - 所以这两种方法实际上是一样的! (7认同)
  • 谢谢,好的答案.它看起来像`buf.ReadFrom()`也读取整个流到EOF. (2认同)

Dim*_*sky 6

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
}
Run Code Online (Sandbox Code Playgroud)


小智 5

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

如果您需要打印从包中接收的数据io.ReadCloser,fmt包可以处理[]byte,但效率不高,因为fmt实现将在内部转换[]bytestring.为了避免这种转换,您可以实现fmt.Formatter类似的类型的接口type ByteSlice []byte.

  • 从`[] byte`到`string`的转换速度相当快,但问题是询问"最有效的方法".目前,在将`[] byte`转换为`string`时,Go运行时总是会分配一个新的`string`.原因是编译器不知道如何确定转换后是否修改`[] byte`.这里有一些编译器优化的空间. (4认同)

yak*_*ada 5

data, _ := ioutil.ReadAll(response.Body)
fmt.Println(string(data))
Run Code Online (Sandbox Code Playgroud)