пятница, 17 июля 2020 г.

Пакет io в Golang, функции чтения

Функция ReadAtLeast

func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error)

ReadAtLeast читает из r в buf, пока не прочитает хотя бы min байтов. Он возвращает количество скопированных байтов и ошибку, если было прочитано меньше байтов. Ошибка EOF, только если не было прочитано ни одного байта. Если EOF происходит после считывания менее чем min байтов, ReadAtLeast возвращает ErrUnexpectedEOF. Если min больше, чем длина буфера, ReadAtLeast возвращает ErrShortBuffer. По возвращении n >= min, только если err == nil. Если r возвращает ошибку, прочитав хотя бы min байтов, ошибка сбрасывается.

package main

import (
    "fmt"
    "io"
    "log"
    "strings"
)

func main() {
    r := strings.NewReader("some io.Reader stream to be read\n")

    buf := make([]byte, 14)
    if _, err := io.ReadAtLeast(r, buf, 4); err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s\n", buf)

    // буфер меньше минимального размера чтения.
    shortBuf := make([]byte, 3)
    if _, err := io.ReadAtLeast(r, shortBuf, 4); err != nil {
        fmt.Println("error:", err)
    }

    // минимальный размер чтения больше, чем поток io.Reader
    longBuf := make([]byte, 64)
    if _, err := io.ReadAtLeast(r, longBuf, 64); err != nil {
        fmt.Println("error:", err)
    }

}

Вывод:

some io.Reader
error: short buffer
error: unexpected EOF

Функция ReadFull

func ReadFull(r Reader, buf []byte) (n int, err error)

ReadFull читает точно len(buf) байтов из r в buf. Он возвращает количество скопированных байтов и ошибку, если было прочитано меньше байтов. Ошибка EOF, только если не было прочитано ни одного байта. Если EOF происходит после чтения некоторых, но не всех байтов, ReadFull возвращает ErrUnexpectedEOF. По возвращении n == len(buf) только тогда, когда err == nil. Если r возвращает ошибку, прочитав по крайней мере len(buf) байтов, ошибка сбрасывается.

package main

import (
    "fmt"
    "io"
    "log"
    "strings"
)

func main() {
    r := strings.NewReader("some io.Reader stream to be read\n")

    buf := make([]byte, 4)
    if _, err := io.ReadFull(r, buf); err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s\n", buf)

    // минимальный размер чтения больше, чем поток io.Reader
    longBuf := make([]byte, 64)
    if _, err := io.ReadFull(r, longBuf); err != nil {
        fmt.Println("error:", err)
    }

}

Вывод:

some
error: unexpected EOF

Тип Reader

Reader - это интерфейс, который оборачивает базовый метод Read.

type Reader interface {
    Read(p []byte) (n int, err error)
}

Read читает до len(p) байтов в p. Он возвращает количество прочитанных байтов (0 <= n <= len(p)) и обнаруженную ошибку. Даже если Read возвращает n < len(p), он может использовать все p как пустое место во время вызова. Если некоторые данные доступны, но не len(p) байтов, Read обычно возвращает то, что доступно, вместо ожидания большего.

Когда Read успешно обнаруживает ошибку или условие конца файла после успешного чтения n > 0 байтов, он возвращает количество прочитанных байтов. Он может вернуть (не nil) ошибку из того же вызова или вернуть ошибку (и n == 0) из последующего вызова. Примером этого общего случая является то, что Reader, возвращающий ненулевое число байтов в конце входного потока, может вернуть либо err == EOF, либо err == nil. Следующее чтение должно вернуть 0, EOF.

Вызывающие всегда должны обрабатывать n > 0 байтов, возвращенных до рассмотрения ошибки err. Это правильно обрабатывает ошибки ввода-вывода, возникающие после чтения некоторых байтов, а также обоих разрешенных вариантов поведения EOF.

Реализации Read не рекомендуется возвращать счетчик нулевых байтов с ошибкой nil, кроме случаев, когда len(p) == 0. Вызывающие операторы должны обрабатывать возврат 0 и nil как указание того, что ничего не произошло; в частности это не указывает на EOF.

Реализации не должны сохранять p (входной срез байтов).

Функция LimitReader

func LimitReader(r Reader, n int64) Reader

LimitReader возвращает Reader, который читает из r, но останавливается с EOF после n байтов. Базовой реализацией является *LimitedReader.

package main

import (
    "io"
    "log"
    "os"
    "strings"
)

func main() {
    r := strings.NewReader("some io.Reader stream to be read\n")
    lr := io.LimitReader(r, 4)

    if _, err := io.Copy(os.Stdout, lr); err != nil {
        log.Fatal(err)
    }

}

Вывод:

some

Функция MultiReader

func MultiReader(readers ...Reader) Reader

MultiReader возвращает Reader, который является логическим объединением предоставленных входных считывателей. Они читаются последовательно. Как только все входы вернут EOF, Read вернет EOF. Если кто-либо из читателей вернет ошибку, отличную от nil, не EOF, Read вернет эту ошибку.

package main

import (
    "io"
    "log"
    "os"
    "strings"
)

func main() {
    r1 := strings.NewReader("first reader ")
    r2 := strings.NewReader("second reader ")
    r3 := strings.NewReader("third reader\n")
    r := io.MultiReader(r1, r2, r3)

    if _, err := io.Copy(os.Stdout, r); err != nil {
        log.Fatal(err)
    }

}

Вывод:

first reader second reader third reader

Функция TeeReader

func TeeReader(r Reader, w Writer) Reader

TeeReader возвращает Reader, который пишет в w то, что он читает из r. Все чтения из r, выполненные через него, сопоставляются с соответствующими записями в w. Внутренняя буферизация отсутствует - запись должна завершиться до завершения чтения. Любая ошибка, обнаруженная во время записи, сообщается как ошибка чтения.

package main

import (
    "bytes"
    "fmt"
    "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)

    printall := func(r io.Reader) {
        b, err := ioutil.ReadAll(r)
        if err != nil {
            log.Fatal(err)
        }

        fmt.Printf("%s", b)
    }

    printall(tee)
    printall(&buf)

}

Вывод:

some io.Reader stream to be read
some io.Reader stream to be read


Читайте также:


Комментариев нет:

Отправить комментарий