Ответ 1
func (b *Reader) Read(p []byte) (n int, err error)
http://golang.org/pkg/bufio/#Reader.Read
Количество прочитанных байтов будет ограничено len(p)
Мне известно о конкретной функции в golang из пакета bufio.
func (b *Reader) Peek(n int) ([]byte, error)
Peek возвращает следующие n байтов без продвижения читателя. Байты перестаньте действовать при следующем вызове чтения. Если Peek возвращает меньше n байтов, он также возвращает ошибку, объясняющую, почему чтение является коротким. ошибка ErrBufferFull, если n больше размера буфера b.
Мне нужно уметь считывать определенное количество байтов из Reader, что будет продвигать читателя. В принципе, идентична функции выше, но она продвигает читателя. Кто-нибудь знает, как это сделать?
func (b *Reader) Read(p []byte) (n int, err error)
http://golang.org/pkg/bufio/#Reader.Read
Количество прочитанных байтов будет ограничено len(p)
Обратите внимание, что метод bufio.Read
вызывает самое большее io.Read
не более одного раза, что означает, что он может вернуть n < len(p)
, не достигнув EOF. Если вы хотите точно прочитать len(p)
bytes или сбой с ошибкой, вы можете использовать io.ReadFull
следующим образом:
n, err := io.ReadFull(reader, p)
Это работает, даже если читатель буферизуется.
Я предпочитаю Read(), особенно если вы собираетесь читать файлы любого типа, и это также может быть полезно при отправке данных в куски, ниже приведен пример, показывающий, как он используется
fs, err := os.Open("fileName");
if err != nil{
fmt.Println("error reading file")
return
}
defer fs.Close()
reader := bufio.NewReader(fs)
buf := make([]byte, 1024)
for{
v, _ := reader.Read(buf) //ReadString and ReadLine() also applicable or alternative
if v == 0{
return
}
//in case it is a string file, you could check its content here...
fmt.Print(string(buf))
}
Передайте читателю буфер размером n байтов.
Для этого вам просто нужно создать байтовый срез и read данные в этот фрагмент с помощью
n := 512
buff := make([]byte, n)
fs.Read(buff) // fs is your reader. Can be like this fs, _ := os.Open('file')
func (b *Reader) Read(p []byte) (n int, err error)
Чтение чтения данных на стр. Он возвращает количество байтов, считанных в p. Байты берутся не более одного Read на базовом Reader, следовательно, n может быть меньше len (p)
TL;DR:
my42bytes, err := ioutil.ReadAll(io.LimitReader(myReader, 42))
Полный ответ:
@monicuta упомянул io.ReadFull
который прекрасно работает. Здесь я приведу другой метод. Он работает путем ioutil.ReadAll
и io.LimitReader
. Позвольте сначала прочитать документ:
$ go doc ioutil.ReadAll func ReadAll(r io.Reader) ([]byte, error) ReadAll reads from r until an error or EOF and returns the data it read. A successful call returns err == nil, not err == EOF. Because ReadAll is defined to read from src until EOF, it does not treat an EOF from Read as an error to be reported. $ go doc io.LimitReader func LimitReader(r Reader, n int64) Reader LimitReader returns a Reader that reads from r but stops with EOF after n bytes. The underlying implementation is a *LimitedReader.
Так что если вы хотите получить 42 байта от читателя myReader
, вы делаете это
import (
"io"
"io/ioutil"
)
func main() {
// myReader := ...
my42bytes, err := ioutil.ReadAll(io.LimitReader(myReader, 42))
if err != nil {
panic(err)
}
//...
}
Вот эквивалентный код с io.ReadFull
$ go doc io.ReadFull func ReadFull(r Reader, buf []byte) (n int, err error) ReadFull reads exactly len(buf) bytes from r into buf. It returns the number of bytes copied and an error if fewer bytes were read. The error is EOF only if no bytes were read. If an EOF happens after reading some but not all the bytes, ReadFull returns ErrUnexpectedEOF. On return, n == len(buf) if and only if err == nil. If r returns an error having read at least len(buf) bytes, the error is dropped.
import (
"io"
)
func main() {
// myReader := ...
buf := make([]byte, 42)
_, err := io.ReadFull(myReader, buf)
if err != nil {
panic(err)
}
//...
}
По сравнению с io.ReadFull
преимущество заключается в том, что вам не нужно вручную создавать buf
, где len(buf)
- это количество байтов, которые вы хотите прочитать, а затем передавать buf
в качестве аргумента при чтении.
Вместо этого вы просто сообщаете io.LimitReader
вы хотите максимум 42 байта от myReader
, и вызываете ioutil.ReadAll
чтобы прочитать их все, возвращая результат в виде байта. В случае успеха возвращаемый фрагмент гарантированно будет иметь длину 42.