Как читать несколько раз из одного io.Reader
Я хочу использовать request.Body(type io.ReadCloser)
, который содержит изображение.
Я не хочу использовать ioutil.ReadAll()
, поскольку я хочу записать это тело непосредственно в файл, а также хочу его декодировать, поэтому я хочу использовать ссылку на контент для последующих вызовов функций,
Я попытался создать несколько экземпляров считывателя, например, показанных ниже
package main
import (
"io/ioutil"
"log"
"strings"
)
func main() {
r := strings.NewReader("some io.Reader stream to be read\n")
a := &r
b := &r
log.Println(ioutil.ReadAll(*a))
log.Println(ioutil.ReadAll(*b))
}
но во втором вызове он всегда выводится в nil
.
Пожалуйста, помогите мне, как я могу передать несколько отдельных ссылок для одного и того же читателя?
Ответы
Ответ 1
io.Reader
рассматривается как поток. Из-за этого вы не можете прочитать это дважды. Представьте себе входящее TCP-соединение. Вы не можете перемотать происходящее.
Но вы можете использовать io.TeeReader
для дублирования потока:
package main
import (
"bytes"
"io"
"io/ioutil"
"log"
"strings"
)
func main() {
r := strings.NewReader("some io.Reader stream to be read\n")
var buf bytes.Buffer
tee := io.TeeReader(r, &buf)
log.Println(ioutil.ReadAll(tee))
log.Println(ioutil.ReadAll(&buf))
}
Пример на Go Playground
Редактировать: Как заметил @mrclx: сначала нужно прочитать из TeeReader
, иначе буфер будет пуст.
Ответ 2
Когда вы вызываете ReadAll
, он будет пустым буфером, поэтому второй вызов всегда ничего не возвращает. Что вы можете сделать, это сохранить результат ReadAll
и повторно использовать его в своих функциях. Например:
bytes, _ := ioutil.ReadAll(r);
log.Println(string(bytes))
Ответ 3
Технически, на одном читателе вы не можете читать несколько раз.
- Даже если вы создаете разные ссылки , но
- когда вы читаете один раз, когда он будет тем же объектом, на который ссылаются все ссылки.
- поэтому вы можете прочитать содержимое и сохранить его в одной переменной.
- Затем используйте эту переменную столько раз, сколько хотите.
Это будет печататься дважды.
package main
import (
"io/ioutil"
"log"
"strings"
)
func main() {
r := strings.NewReader("some io.Reader stream to be read\n")
stringData, _ := ioutil.ReadAll(r)
log.Println(stringData)
log.Println(stringData)
}
Ответ 4
@TheHippo ответ правильный, я просто хотел добавить это (но не смог добавить его, потому что у меня всего 49 репутации :(): важно, чтобы вы сначала использовали TeeReader, а после вы использовали буфер, куда копируется информация, в противном случае - второй. буфер будет пуст.