我有一个 io.ReadCloser对象(来自一个 http.Response对象)。
io.ReadCloser
http.Response
将整个流转换为 string对象的最有效方法是什么?
string
我喜欢 字节缓冲区结构。我看到它有 读取自和 绳子方法。我用的是字节[]但不是输入输出。读者。
最有效的方法是始终使用 []byte而不是 string。
[]byte
如果您需要打印从 io.ReadCloser接收到的数据,fmt包可以处理 []byte,但是效率不高,因为 fmt实现将在内部将 []byte转换为 string。为了避免这种转换,您可以为类似于 type ByteSlice []byte的类型实现 fmt.Formatter接口。
fmt
type ByteSlice []byte
fmt.Formatter
编辑:
从1.10开始,字符串.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.
这个副本是作为一个保护机制完成的。字符串是不可变的。如果可以将[]字节转换为字符串,则可以更改字符串的内容。但是,go 允许您使用不安全的包禁用类型安全机制。使用不安全软件包的风险自负。希望这个名字本身就是一个很好的警告。下面是我使用不安全的方法:
buf := new(bytes.Buffer) buf.ReadFrom(yourReader) b := buf.Bytes() s := *(*string)(unsafe.Pointer(&b))
现在,您已经有效地将字节数组转换为字符串。实际上,这样做只是欺骗类型系统将其调用为字符串。这种方法有几个注意事项:
我的建议是坚持官方的方法。做一个副本是不是昂贵的 那个和它是不值得的邪恶的不安全。如果字符串太大而无法复制,则不应将其制作成字符串。
到目前为止,答案还没有回答这个问题的“整个流”部分。我认为这样做的好方法是 ioutil.ReadAll。用你的 io.ReaderCloser命名为 rc,我会写,
ioutil.ReadAll
io.ReaderCloser
rc
Go > = v1.16
if b, err := io.ReadAll(rc); err == nil { return string(b) } ...
去 < = v1.15
if b, err := ioutil.ReadAll(rc); err == nil { return string(b) } ...
data, _ := ioutil.ReadAll(response.Body) fmt.Println(string(data))
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()