У меня есть объект io.ReadCloser
(из объекта http.Response
).
Каков наиболее эффективный способ преобразования всего потока в объект string
?
У меня есть объект io.ReadCloser
(из объекта http.Response
).
Каков наиболее эффективный способ преобразования всего потока в объект 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
я бы написал,
if b, err := ioutil.ReadAll(rc); err == nil {
return string(b)
} ...
Самый эффективный способ - всегда использовать []byte
вместо string
.
В случае, если вам нужно распечатать данные, полученные из io.ReadCloser
, пакет fmt
может обрабатывать []byte
, но это неэффективно, потому что реализация fmt
внутренне преобразует []byte
в string
. Чтобы избежать этого преобразования, вы можете реализовать интерфейс fmt.Formatter
для типа, подобного type ByteSlice []byte
.
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
}
Мне нравится bytes.Buffer struct. Я вижу, что ReadFrom и String методы, Я использовал его с байт [], но не io.Reader.
var b bytes.Buffer
b.ReadFrom(r)
// b.String()