Ответы:
РЕДАКТИРОВАТЬ:
Начиная с версии 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.
Эта копия сделана как механизм защиты. Строки неизменны. Если бы вы могли преобразовать байт [] в строку, вы могли бы изменить содержимое строки. Однако 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
я бы написал,
if b, err := ioutil.ReadAll(rc); err == nil {
return string(b)
} ...
buf.ReadFrom()
также читает весь поток до EOF.
ioutil.ReadAll()
и просто обертывания bytes.Buffer
«S ReadFrom
. А метод буфера String()
- это простой переход на приведение к string
- так что два подхода практически одинаковы!
data, _ := ioutil.ReadAll(response.Body)
fmt.Println(string(data))
Самый эффективный способ - всегда использовать []byte
вместоstring
.
Если вам нужно распечатать данные, полученные от io.ReadCloser
, fmt
пакет может обрабатывать []byte
, но это неэффективно, потому что fmt
реализация будет внутренне преобразована []byte
в string
. Чтобы избежать этого преобразования, вы можете реализовать fmt.Formatter
интерфейс для такого типа, как type ByteSlice []byte
.
[]byte
в string
происходит достаточно быстро, но вопрос был о «наиболее эффективном способе». В настоящее время среда выполнения Go всегда выделяет новую string
при преобразовании []byte
в 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 . Я использовал его с байтом [], но не с io.Reader.