Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як обробити CSV-файл на кілька гігабайтів, не вичерпавши пам'ять?

Головне правило - ніколи не тримати в пам'яті весь файл і не накопичувати результати. Читати рядок за рядком і одразу обробляти.

Читання потоком:

function rows(string $path): Generator
{
    $file = new SplFileObject($path);
    $file->setFlags(SplFileObject::READ_CSV | SplFileObject::SKIP_EMPTY | SplFileObject::READ_AHEAD);

    $header = null;
    foreach ($file as $row) {
        if ($header === null) {
            $header = $row;
            continue;
        }
        yield array_combine($header, $row);
    }
}

Генератор віддає по одному рядку, тож пам'ять стала незалежно від розміру файлу.

Запис у базу - порціями:

$batch = [];
foreach (rows('import.csv') as $row) {
    $batch[] = ['email' => $row['email'], 'name' => $row['name']];

    if (count($batch) === 1000) {
        DB::table('subscribers')->insert($batch);
        $batch = [];
    }
}
if ($batch !== []) {
    DB::table('subscribers')->insert($batch);
}

Вставка по одному рядку - мільйон запитів; порціями по 1000 - тисяча. Масова вставка через query builder ще й не створює моделей і не запускає подій.

Що ще враховувати:

  • Кодування й роздільник: CSV з Excel часто в Windows-1251 і з ;. Перекодування на льоту - потоковим фільтром (php://filter/read=convert.iconv.windows-1251/utf-8/resource=...).
  • Логування запитів вимкнене: DB::enableQueryLog() у довгому імпорті накопичує всі запити в пам'яті.
  • Помилки в окремих рядках не мають зупиняти весь імпорт - збирати їх у звіт.
  • Перервність: запам'ятовувати номер обробленого рядка, щоб продовжити після збою, а не починати спочатку.
  • Черга: великий імпорт з веб-інтерфейсу - завдання в черзі, а не синхронний запит.

У Laravel те саме зручно робити через LazyCollection::make(fn () => yield from rows(...))->chunk(1000).

Докладніше в документації: SplFileObject

1

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання