Подтвердить что ты не робот

Чтение определенного количества байтов из буферизованного считывателя в golang

Мне известно о конкретной функции в golang из пакета bufio.

func (b *Reader) Peek(n int) ([]byte, error)

Peek возвращает следующие n байтов без продвижения читателя. Байты перестаньте действовать при следующем вызове чтения. Если Peek возвращает меньше n байтов, он также возвращает ошибку, объясняющую, почему чтение является коротким. ошибка ErrBufferFull, если n больше размера буфера b.

Мне нужно уметь считывать определенное количество байтов из Reader, что будет продвигать читателя. В принципе, идентична функции выше, но она продвигает читателя. Кто-нибудь знает, как это сделать?

4b9b3361

Ответ 1

func (b *Reader) Read(p []byte) (n int, err error)

http://golang.org/pkg/bufio/#Reader.Read

Количество прочитанных байтов будет ограничено len(p)

Ответ 2

Обратите внимание, что метод bufio.Read вызывает самое большее io.Read не более одного раза, что означает, что он может вернуть n < len(p), не достигнув EOF. Если вы хотите точно прочитать len(p) bytes или сбой с ошибкой, вы можете использовать io.ReadFull следующим образом:

n, err := io.ReadFull(reader, p)

Это работает, даже если читатель буферизуется.

Ответ 3

Я предпочитаю 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))
}

Ответ 4

Передайте читателю буфер размером n байтов.

Ответ 5

Для этого вам просто нужно создать байтовый срез и 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)

Ответ 6

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.