Функция io.TeeReader

Функция io.TeeReader возвращает новый io.Reader, который читает данные из переданного ей ридера и одновременно записывает все прочитанные данные в указанный врайтер. В первый параметр мы передаем исходный ридер для чтения данных, во второй параметр мы передаем врайтер, в который будут дублироваться прочитанные данные.

Синтаксис

goio.TeeReader(reader io.Reader, writer io.Writer) io.Reader

Пример использования с файлами

Давайте прочитаем данные из файла и одновременно запишем их в другой файл с помощью io.TeeReader:

gopackage main

import (
  "io"
  "os"
)

func main() {
  srcFile, err := os.Open("source.txt")
  if err != nil {
    panic(err)
  }
  defer srcFile.Close()

  dstFile, err := os.Create("destination.txt")
  if err != nil {
    panic(err)
  }
  defer dstFile.Close()

  teeReader := io.TeeReader(srcFile, dstFile)

  data, err := io.ReadAll(teeReader)
  if err != nil {
    panic(err)
  }

  os.Stdout.Write(data)
}

В этом примере данные из source.txt одновременно читаются и записываются в destination.txt, а также выводятся в стандартный вывод.

Пример с подсчетом байт

Давайте используем io.TeeReader для подсчета количества прочитанных байт:

gopackage main

import (
  "bytes"
  "fmt"
  "io"
)

type Counter struct {
  count int64
}

func (c *Counter) Write(p []byte) (int, error) {
  c.count += int64(len(p))
  return len(p), nil
}

func main() {
  data := []byte("hello world")
  reader := bytes.NewReader(data)
  counter := &Counter{}

  teeReader := io.TeeReader(reader, counter)

  res, err := io.ReadAll(teeReader)
  if err != nil {
    panic(err)
  }

  fmt.Printf("Прочитано данных: %s\n", string(res))
  fmt.Printf("Количество байт: %d\n", counter.count)
}

Результат выполнения кода:

go"Прочитано данных: hello world"
"Количество байт: 11"

Пример с несколькими врайтерами

Давайте создадим несколько врайтеров и объединим их с помощью io.MultiWriter:

gopackage main

import (
  "bytes"
  "fmt"
  "io"
  "os"
)

func main() {
  data := []byte("abcde")
  reader := bytes.NewReader(data)

  var buf1, buf2 bytes.Buffer
  multiWriter := io.MultiWriter(&buf1, &buf2, os.Stdout)

  teeReader := io.TeeReader(reader, multiWriter)

  res, err := io.ReadAll(teeReader)
  if err != nil {
    panic(err)
  }

  fmt.Printf("\nRead all: %s\n", string(res))
  fmt.Printf("Buffer 1: %s\n", buf1.String())
  fmt.Printf("Buffer 2: %s\n", buf2.String())
}

Результат выполнения кода:

go"abcde"
"Read all: abcde"
"Buffer 1: abcde"
"Buffer 2: abcde"

Смотрите также

  • функцию io.ReadAll,
    которая читает все данные из ридера до конца
  • функцию io.MultiWriter,
    которая объединяет несколько врайтеров в один
  • функцию io.Copy,
    которая копирует данные из ридера во врайтер
  • интерфейс io.Reader,
    который определяет базовый интерфейс для чтения данных