Skip to content

Пакет io: правила чтения и потоковые данные

Поведение средства reader будет зависеть от его реализации, однако есть несколько правил из документа io.Reader, о которых ты должен знать при использовании непосредственно из средства reader’а:

  1. Read() будет читать до len(p) в p, если возможно.

  2. После Read() звонка n может быть меньше len(p).

  3. В случае ошибки Read() может по-прежнему возвращать n байты в буфере p. Например, чтение из внезапно закрытого TCP-сокета. В зависимости от использования ты можешь сохранить байты p или повторить попытку.

  4. Когда в Read() исчерпываются доступные данные, считыватель может вернуть ненулевое значение n и err = io.EOF. Однако в зависимости от реализации, reader может выбрать возврат ненулевого значения n и err = nil в конце потока. В этом случае любые последующие операции чтения должны возвращать n = 0, err = io.EOF.

  5. Наконец, вызов в Read(), который возвращает n = 0, а также err = nil не означает EOF как следующий вызов Read(), может вернуть больше данных.

Как мы видим, правильное чтение потока непосредственно из reader’a может оказаться непростой задачей. К счастью, reader’ы из стандартной библиотеки следуют разумным подходам, облегчающим потоковую передачу. Тем не менее, прежде чем использовать reader, ознакомься с его документацией.

Потоковые данные из reader’ов

Потоковая передача данных непосредственно из reader’а очень проста. Метод Read предназначен для вызова внутри цикла, где на каждой итерации он считывает порцию данных из источника и помещает ее в буфер p. Этот цикл будет продолжаться до тех пор, пока метод не вернет io.EOF ошибку.

Ниже приведен простой пример, в котором используется reader строк, созданное с помощью strings.NewReader(string), для потоковой передачи значений байтов из источника строк.

Пришло время поработать с кодом!

Приведенный выше исходный код создает буфер передачи длиной 4 байта p с расширением make([]byte,4). Буфер намеренно поддерживается меньшим, чем длина источника строки. Это должно продемонстрировать, как правильно передавать фрагменты данных из источника, который больше, чем буфер.

Реализация пользовательского io.Reader

Ранее мы рассмотрели существующую реализацию считывателя ввода-вывода из стандартной библиотеки. Теперь давай посмотрим, как написать собственную реализацию. Ниже приведена тривиальная реализация, io.Reader которая отфильтровывает неалфавитные символы из своего потока.

Пришло время поработать с кодом!

Когда программа выполняется, она печатает.