У меня есть io.ReadCloser
объект (из http.Response
объекта).
Какой самый эффективный способ преобразовать весь поток в string
объект?
РЕДАКТИРОВАТЬ:
Начиная с версии 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
я бы написал,источник
buf.ReadFrom()
также читает весь поток до EOF.ioutil.ReadAll()
и просто обертыванияbytes.Buffer
«SReadFrom
. А метод буфераString()
- это простой переход на приведение кstring
- так что два подхода практически одинаковы!источник
Самый эффективный способ - всегда использовать
[]byte
вместоstring
.Если вам нужно распечатать данные, полученные от
io.ReadCloser
,fmt
пакет может обрабатывать[]byte
, но это неэффективно, потому чтоfmt
реализация будет внутренне преобразована[]byte
вstring
. Чтобы избежать этого преобразования, вы можете реализоватьfmt.Formatter
интерфейс для такого типа, какtype ByteSlice []byte
.источник
[]byte
вstring
происходит достаточно быстро, но вопрос был о «наиболее эффективном способе». В настоящее время среда выполнения Go всегда выделяет новуюstring
при преобразовании[]byte
вstring
. Причина этого в том, что компилятор не знает, как определить,[]byte
будет ли изменен после преобразования. Здесь есть место для оптимизации компилятора.источник
источник
Мне нравится структура bytes.Buffer . Я вижу, что у него есть методы ReadFrom и String . Я использовал его с байтом [], но не с io.Reader.
источник