Ошибка io.ErrUnexpectedEOF

Ошибка io.ErrUnexpectedEOF возникает, когда операция чтения не может прочитать запрошенное количество байт, хотя поток данных еще не достиг конечной метки EOF. В отличие от обычной ошибки io.EOF, которая означает корректное завершение чтения, данная ошибка свидетельствует о том, что данные повреждены или оборваны преждевременно. Особенно часто с этой ошибкой сталкиваются при работе с бинарными форматами данных, архивами, сетевыми протоколами или любыми структурированными данными, где четко определены размеры блоков.

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

Синтаксис

gofunc Read(r io.Reader, buf []byte) (int, error)

Пример возникновения ошибки io.ErrUnexpectedEOF

Давайте рассмотрим ситуацию, когда мы пытаемся прочитать из файла ровно 100 байт, но файл содержит только 50 байт:

gopackage main

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

func main() {
  data := []byte("short file")
  os.WriteFile("test.txt", data, 0644)

  file, err := os.Open("test.txt")
  if err != nil {
    fmt.Println("Error:", err)
    return
  }
  defer file.Close()

  buf := make([]byte, 100)
  n, err := io.ReadFull(file, buf)
  if err != nil {
    fmt.Printf("Read bytes: %d, Error: %v\n", n, err)
    return
  }
  fmt.Printf("Successfully read %d bytes\n", n)
}

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

go"Read bytes: 10, Error: unexpected EOF"

Пример проверки на io.ErrUnexpectedEOF

Рассмотрим, как правильно обрабатывать ошибку и отличать ее от корректного конца файла:

gopackage main

import (
  "errors"
  "fmt"
  "io"
  "os"
)

func main() {
  data := []byte("abcde")
  os.WriteFile("test.txt", data, 0644)

  file, err := os.Open("test.txt")
  if err != nil {
    fmt.Println("Error:", err)
    return
  }
  defer file.Close()

  buf := make([]byte, 3)
  _, err = io.ReadFull(file, buf)
  if err != nil {
    if errors.Is(err, io.ErrUnexpectedEOF) {
      fmt.Println("File is truncated: unexpected EOF")
    } else if errors.Is(err, io.EOF) {
      fmt.Println("End of file reached correctly")
    } else {
      fmt.Println("Other error:", err)
    }
    return
  }
  fmt.Println("Data read successfully:", string(buf))
}

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

go"Data read successfully: abc"

Пример использования io.ReadAtLeast

Функция io.ReadAtLeast также может вернуть ошибку io.ErrUnexpectedEOF, если не удалось прочитать минимальное количество байт:

gopackage main

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

func main() {
  reader := strings.NewReader("hello")
  buf := make([]byte, 10)

  n, err := io.ReadAtLeast(reader, buf, 5)
  if err != nil {
    fmt.Printf("Read %d bytes, Error: %v\n", n, err)
    return
  }
  fmt.Printf("Read %d bytes: %s\n", n, string(buf[:n]))
}

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

go"Read 5 bytes, Error: unexpected EOF"

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

  • функцию io.ReadFull,
    которая читает ровно заданное количество байт
  • функцию io.ReadAtLeast,
    которая читает как минимум указанное количество байт
  • ошибку io.EOF,
    которая возникает при корректном окончании чтения
  • функцию os.File.Read,
    которая читает данные из открытого файла