Как в Go эффективно читать большие объемы данных (например, из файла), не загружая все содержимое в память?

Ответ

Для эффективного чтения больших объемов данных в Go, чтобы избежать ошибок нехватки памяти (out-of-memory), используется потоковое чтение (streaming). Основные инструменты для этого находятся в пакете bufio.

1. Использование bufio.Scanner (для построчного чтения)

Это самый простой и предпочтительный способ для чтения текстовых файлов по строкам.

file, err := os.Open("large_log_file.txt")
if err != nil {
    log.Fatal(err)
}
defer file.Close()

scanner := bufio.NewScanner(file)
// Сканируем файл построчно
for scanner.Scan() {
    line := scanner.Text() // Получаем текущую строку
    // process(line)
}

if err := scanner.Err(); err != nil {
    log.Fatal(err)
}

2. Использование bufio.Reader (для чтения по частям/байтам)

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

file, err := os.Open("large_binary_file.bin")
if err != nil {
    log.Fatal(err)
}
defer file.Close()

reader := bufio.NewReader(file)
buffer := make([]byte, 4096) // Буфер для чтения, например 4KB

for {
    // Читаем данные в буфер
    n, err := reader.Read(buffer)
    if err != nil {
        if err == io.EOF { // Если достигнут конец файла, выходим
            break
        }
        log.Fatal(err)
    }
    // Обрабатываем прочитанный кусок данных (n байт)
    // processChunk(buffer[:n])
}

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