从io.Reader到Go中的字符串

时间:2012-03-10 05:19:32

标签: go

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

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

7 个答案:

答案 0 :(得分:154)

简短的回答是它效率不高,因为转换为字符串需要完整地复制字节数组。这是做你想做的事情的正确(非效率)方式:

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

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

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

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

  1. 无法保证这将适用于所有编译器。虽然这适用于plan-9 gc编译器,但它依赖于"实现细节"在官方规范中没有提到。您甚至不能保证这将适用于所有体系结构或不在gc中更改。换句话说,这是一个坏主意。
  2. 那个字符串是可变的!如果您在该缓冲区上进行任何调用,更改字符串。要非常小心。
  3. 我的建议是坚持官方方法。复制不是 昂贵的,不值得不安全的邪恶。如果字符串太大而无法复制,则不应将其变为字符串。

答案 1 :(得分:88)

到目前为止,答案还没有解决问题的“整个流”部分。我认为这样做的好方法是ioutil.ReadAll。使用名为io.ReaderCloser的{​​{1}},我会写,

rc

答案 2 :(得分:5)

最有效的方法是始终使用[]byte代替string

如果您需要打印从io.ReadCloser收到的数据,fmt包可以处理[]byte,但效率不高,因为fmt实施将在内部将[]byte转换为string。为了避免此转化,您可以为type ByteSlice []byte类型实施fmt.Formatter界面。

答案 3 :(得分:4)

data, _ := ioutil.ReadAll(response.Body)
fmt.Println(string(data))

答案 4 :(得分:1)

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
}

答案 5 :(得分:0)

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

答案 6 :(得分:0)

var b bytes.Buffer
b.ReadFrom(r)

// b.String()