Тип bufio.Reader

Тип bufio.Reader представляет собой буферизированный ридер, который оборачивает стандартный ридер (например, os.Stdin или strings.Reader) и предоставляет дополнительные методы для удобного чтения данных. Буферизация позволяет уменьшить количество системных вызовов при чтении данных, что повышает производительность. В первый параметр функции bufio.NewReader мы передаем источник данных (ридер), а результатом работы является указатель на новый экземпляр bufio.Reader.

Создание ридера

Для создания буферизированного ридера используется функция bufio.NewReader, которая принимает интерфейс io.Reader. Рассмотрим базовый пример создания ридера из строки:

gopackage main

import (
  "bufio"
  "fmt"
  "strings"
)

func main() {
  str := "abcde"
  reader := bufio.NewReader(strings.NewReader(str))
  fmt.Println(reader)
}

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

go&{0xc0000120c0 0 0 0 0}

Метод ReadString

Метод ReadString читает данные из буфера до тех пор, пока не встретит указанный разделитель (обычно это символ новой строки). Он возвращает прочитанную строку вместе с разделителем. В первый параметр метода мы передаем разделитель в виде байта, а результатом является строка и ошибка:

gopackage main

import (
  "bufio"
  "fmt"
  "strings"
)

func main() {
  str := "Hello\nWorld\nGo"
  reader := bufio.NewReader(strings.NewReader(str))

  line, err := reader.ReadString('\n')
  if err != nil {
    fmt.Println("Error:", err)
    return
  }
  fmt.Println(line)
}

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

go"Hello\n"

Метод ReadBytes

Метод ReadBytes работает аналогично ReadString, но возвращает срез байтов вместо строки. Это полезно, когда мы работаем с бинарными данными или когда строка может содержать невалидные UTF-8 символы:

gopackage main

import (
  "bufio"
  "fmt"
  "strings"
)

func main() {
  data := "12345\n67890"
  reader := bufio.NewReader(strings.NewReader(data))

  bytes, err := reader.ReadBytes('\n')
  if err != nil {
    fmt.Println("Error:", err)
    return
  }
  fmt.Println(bytes)
}

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

go[49 50 51 52 53 10]

Метод ReadLine

Метод ReadLine читает строку текста и возвращает ее в виде среза байтов без завершающего символа новой строки. В отличие от ReadString, этот метод удаляет разделитель. Результатом работы метода являются срез байтов, булев флаг (указывающий, была ли строка слишком длинной) и ошибка:

gopackage main

import (
  "bufio"
  "fmt"
  "strings"
)

func main() {
  text := "First line\nSecond line"
  reader := bufio.NewReader(strings.NewReader(text))

  line, isPrefix, err := reader.ReadLine()
  if err != nil {
    fmt.Println("Error:", err)
    return
  }
  fmt.Println(string(line))
  fmt.Println("isPrefix:", isPrefix)
}

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

go"First line"
"isPrefix: false"

Метод Peek

Метод Peek позволяет заглянуть вперед на указанное количество байтов, не извлекая их из буфера. Это полезно, когда нужно проверить следующие данные перед тем, как принять решение о чтении. В первый параметр передается количество байтов для просмотра, а результатом является срез байтов и ошибка:

gopackage main

import (
  "bufio"
  "fmt"
  "strings"
)

func main() {
  data := "12345"
  reader := bufio.NewReader(strings.NewReader(data))

  peeked, err := reader.Peek(3)
  if err != nil {
    fmt.Println("Error:", err)
    return
  }
  fmt.Println(peeked)
  fmt.Println(string(peeked))

  // Буфер не изменился, можем прочитать полностью
  all, _ := reader.ReadString('\n')
  fmt.Println(all)
}

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

go[49 50 51]
"123"
"12345"

Метод Discard

Метод Discard пропускает указанное количество байтов из буфера, не возвращая их. Это полезно, когда нужно пропустить неинтересующие нас данные. В первый параметр передается количество байтов для пропуска, а результатом является количество реально пропущенных байтов и ошибка:

gopackage main

import (
  "bufio"
  "fmt"
  "strings"
)

func main() {
  data := "abcde"
  reader := bufio.NewReader(strings.NewReader(data))

  discarded, err := reader.Discard(2)
  if err != nil {
    fmt.Println("Error:", err)
    return
  }
  fmt.Println("Discarded:", discarded)

  remaining, _ := reader.ReadString('\n')
  fmt.Println(remaining)
}

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

go"Discarded: 2"
"cde"

Метод Buffered

Метод Buffered возвращает количество байтов, которые в настоящее время находятся в буфере и доступны для чтения. Это позволяет контролировать состояние буфера и принимать решения о дальнейших действиях:

gopackage main

import (
  "bufio"
  "fmt"
  "strings"
)

func main() {
  data := "abcde"
  reader := bufio.NewReader(strings.NewReader(data))

  fmt.Println("Buffered:", reader.Buffered())

  reader.ReadByte()
  reader.ReadByte()

  fmt.Println("Buffered after reads:", reader.Buffered())
}

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

go"Buffered: 5"
"Buffered after reads: 3"

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

  • тип bufio.Writer,
    который предоставляет буферизированную запись данных
  • тип bufio.Scanner,
    который удобен для построчного чтения данных
  • функцию bufio.NewReader,
    которая создает новый буферизированный ридер
  • метод bufio.Reader.ReadString,
    который читает данные до указанного разделителя