Mam io.ReadCloser
obiekt (z http.Response
obiektu).
Jaki jest najbardziej efektywny sposób przekształcenia całego strumienia w string
obiekt?
EDYTOWAĆ:
Od 1.10 istnieje strings.Builder. Przykład:
buf := new(strings.Builder)
n, err := io.Copy(buf, r)
// check errors
fmt.Println(buf.String())
NIEAKTUALNE INFORMACJE PONIŻEJ
Krótka odpowiedź jest taka, że nie będzie to efektywne, ponieważ konwersja na łańcuch wymaga wykonania pełnej kopii tablicy bajtów. Oto właściwy (nieefektywny) sposób robienia tego, co chcesz:
buf := new(bytes.Buffer)
buf.ReadFrom(yourReader)
s := buf.String() // Does a complete copy of the bytes in the buffer.
Ta kopia jest wykonywana jako mechanizm ochronny. Ciągi znaków są niezmienne. Gdybyś mógł przekonwertować [] bajt na łańcuch, mógłbyś zmienić zawartość łańcucha. Jednak go pozwala wyłączyć mechanizmy bezpieczeństwa typu przy użyciu niebezpiecznego pakietu. Używaj niebezpiecznego pakietu na własne ryzyko. Miejmy nadzieję, że sama nazwa jest wystarczająco dobrym ostrzeżeniem. Oto, jak zrobiłbym to, używając niebezpiecznego:
buf := new(bytes.Buffer)
buf.ReadFrom(yourReader)
b := buf.Bytes()
s := *(*string)(unsafe.Pointer(&b))
Proszę bardzo, teraz skutecznie przekonwertowałeś swoją tablicę bajtów na łańcuch. Naprawdę wszystko to oszukuje system typów, aby nazwał go łańcuchem. Istnieje kilka zastrzeżeń dotyczących tej metody:
Radzę trzymać się oficjalnej metody. Robi kopię nie jest to drogie i nie warto zło niebezpieczne. Jeśli ciąg jest zbyt duży, aby wykonać kopię, nie powinieneś tworzyć z niego łańcucha.
strings.Builder
robi to skutecznie, upewniając się, że baza[]byte
nigdy nie przecieka i konwertuje do wersjistring
bez kopii w sposób, który będzie obsługiwany w przyszłości. To nie istniało w 2012 roku. Poniższe rozwiązanie @ dimchansky jest poprawne od wersji Go 1.10. Rozważ zmianę!Dotychczasowe odpowiedzi nie dotyczyły części pytania dotyczącej „całego strumienia”. Myślę, że dobrym sposobem na to jest
ioutil.ReadAll
. Z twoimio.ReaderCloser
imieniemrc
napisałbym,if b, err := ioutil.ReadAll(rc); err == nil { return string(b) } ...
źródło
buf.ReadFrom()
odczytuje również cały strumień aż do EOF.ioutil.ReadAll()
i po prostu owijabytes.Buffer
„sReadFrom
. AString()
metoda bufora polega na prostym rzutowaniu dookołastring
- więc te dwa podejścia są praktycznie takie same!data, _ := ioutil.ReadAll(response.Body) fmt.Println(string(data))
źródło
Najbardziej efektywnym sposobem byłoby zawsze używanie
[]byte
zamiaststring
.W przypadku, gdy musisz wydrukować dane otrzymane z
io.ReadCloser
,fmt
pakiet może obsłużyć[]byte
, ale nie jest to wydajne, ponieważfmt
implementacja zostanie wewnętrznie przekonwertowana[]byte
nastring
. Aby uniknąć tej konwersji, możesz zaimplementowaćfmt.Formatter
interfejs dla typutype ByteSlice []byte
.źródło
[]byte
nastring
jest dość szybka, ale pytanie dotyczyło „najbardziej wydajnego sposobu”. Obecnie środowisko wykonawcze Go zawsze przydziela nowystring
podczas konwersji[]byte
dostring
. Powodem tego jest to, że kompilator nie wie, jak określić, czy[]byte
plik zostanie zmodyfikowany po konwersji. Jest tu miejsce na optymalizacje kompilatora.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 }
źródło
var b bytes.Buffer b.ReadFrom(r) // b.String()
źródło
Podoba mi się struktura bytes.Buffer . Widzę, że ma metody ReadFrom i String . Użyłem go z [] bajtem, ale nie z io.Reader.
źródło