Назад к урокам

Readers и Writers в Go

Урок объясняет, как работают интерфейсы io.Reader и io.Writer в Go, как читать и записывать данные блоками, зачем нужны буферизированные обёртки из bufio, и как использовать bufio.Scanner для удобной обработки текстового ввода.

Начинающий12 min

📚 Readers и Writers в Go

В Go входные и выходные данные обрабатываются через универсальные интерфейсы Reader и Writer. Эти интерфейсы позволяют читать и записывать данные из различных источников: файлов, сетевых соединений, буферов, строк и многого другого.


📌 Reader и Writer --- что это?

Go предоставляет два ключевых интерфейса:

Reader

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

Writer

type Writer interface {
    Write(p []byte) (n int, err error)
}

Они определяют минимальный набор поведения для чтения и записи данных.

Reader --- читает данные в предоставленный буфер. Writer --- записывает данные из буфера.


🧠 Как работает Reader

При каждом вызове:

  • Read() заполняет предоставленный буфер p байтами,
  • возвращает количество прочитанных байт n,
  • возвращает ошибку io.EOF, когда данные закончились.

Пример чтения блоками:

reader := strings.NewReader("SAMPLE")

var result strings.Builder
buffer := make([]byte, 4)

for {
    n, err := reader.Read(buffer)
    chunk := buffer[:n]
    result.Write(chunk)

    fmt.Printf("Read %v bytes: %c
", n, chunk)

    if err == io.EOF {
        break
    }
}

fmt.Println(result.String())

🧱 Пошаговое объяснение примера

В примере ниже строка "SAMPLE" читается частями размером 4 байта:

Итерация Прочитано Байты Результат


1 4 S A M P SAMP 2 2 L E SAMPLE 3 0 [] завершено

Так работает чтение блоками --- Reader читает ровно столько, сколько помещается в буфер.


📝 Writer

Writer во многом симметричен Reader:

  • получает буфер байтов,
  • записывает его содержимое,
  • возвращает количество записанных байт.

Пример:

writer := &strings.Builder{}
writer.Write([]byte("Go!"))
fmt.Println(writer.String()) // Go!

⚙️ Буферизация с помощью bufio

Go предоставляет пакет bufio, который реализует буферизированные Reader и Writer.

Преимущества:

  • меньше обращений к реальному источнику данных,
  • выше производительность,
  • удобные методы, такие как ReadString, ReadBytes, WriteString.

Пример:

r := bufio.NewReader(os.Stdin)
line, _ := r.ReadString('
')
fmt.Println("You entered:", line)

🧾 Сканирование текста --- bufio.Scanner

Scanner автоматизирует разбор входных данных на части:

  • построчно,
  • по словам,
  • по кастомному разделителю.

Пример чтения строк:

scanner := bufio.NewScanner(os.Stdin)
lines := []string{}

for scanner.Scan() {
    lines = append(lines, scanner.Text())
}

if scanner.Err() != nil {
    fmt.Println(scanner.Err())
}

fmt.Printf("Line count: %v
", len(lines))
for _, line := range lines {
    fmt.Println("Line:", line)
}

📘 Итоги

  • Reader и Writer - универсальные интерфейсы для чтения и записи данных.
  • Reader заполняет буфер байтами, Writer записывает байты из буфера.
  • Через буферы можно читать данные частями.
  • Пакет bufio предоставляет улучшенные, буферизированные версии.
  • bufio.Scanner идеально подходит для разбора текстовых потоков.