Разбор CSV в FastExcelReader

Источник: 4.5.0 · dd0d48d

На этой странице

Быстрый и эффективный CSV-ридер для PHP, встроенный в пакет fast-excel-reader. Он поддерживает различные кодировки, автоопределение разделителя и обработку больших файлов.

Содержание

  1. Возможности
  2. Базовое использование
  3. Продвинутое чтение
  4. Опции конфигурации
  5. Обработка ошибок
  6. Примеры
  7. Справочник API

Возможности

  • Определение разделителя: автоматическое или ручное указание разделителя колонок.
  • Широкая поддержка кодировок:
    • UTF-8, UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE
    • Windows-1251, KOI8-R, ISO-8859-5
    • CP932, Shift_JIS, EUC-JP
    • Любая кодировка, поддерживаемая вашим окружением PHP.
  • Соответствие RFC 4180: поддержка полей с кавычками и без, а также экранированных кавычек (удвоенных).
  • Многострочные поля: обработка переносов строк внутри полей в кавычках.
  • Гибкий разбор:
    • Строгий режим: строго следует RFC 4180.
    • Толерантный режим: более снисходителен к нестандартным CSV-файлам (например, кавычки внутри полей без кавычек).
  • Экономия памяти: способен читать очень большие файлы построчно с помощью генераторов.
  • Дополнительные утилиты: пропуск пустых строк, пропуск строк-комментариев, обрезка полей, произвольные ограничители и экранирующие символы.
  • Обработка BOM: автоматическая обработка файлов с меткой порядка байтов (Byte Order Mark).

Базовое использование

Какую фабрику выбрать

Excel::openCsvBook($file, $options) возвращает типизированную CSV-книгу с общим API sheet()/readRows(). Excel::openCsvReader($file, $options) открывает низкоуровневый движок с getCsvLine()/fromRow(). Обе фабрики принимают массив, CsvOptions или null и допускают пустой CSV. Универсальный Excel::open() определяет формат по содержимому и отклоняет пустой файл; ['format' => 'csv'] принудительно выбирает CSV.

В 4.x старый Excel::openCsv() сохраняет возврат CsvReader. В 5.0 планируется возврат CsvBook: для сохранения низкоуровневого контракта замените имя на openCsvReader(). Для общего API книги сразу используйте openCsvBook(). Доступ к движку уже открытой книги остаётся доступен через $book->getReader().

php
$book = Excel::openCsvBook('data.csv', ['delimiter' => ';']);
$rows = $book->sheet()->readRows();
$reader = Excel::openCsvReader('data.csv', ['delimiter' => ';']);
$line = $reader->getCsvLine();

Проще всего открыть CSV-файл через метод Excel::openCsvReader().

php
use avadim\FastExcelReader\Excel;

$file = 'data.csv';
$csv = Excel::openCsvReader($file);

foreach ($csv->nextRow() as $rowNum => $row) {
    // $row — это простой числовой массив
    print_r($row);
}

Открытие CSV как обычного файла через Excel::open()

Начиная с v4.2.0 универсальная точка входа Excel::open() принимает и CSV-файлы, возвращая обычный файл, — то есть CSV ведёт себя как любая другая таблица: у него один лист с тем же API, что у XLSX и XLS (sheet(), nextRow(), readRows(), readColumns(), setReadArea(), withHeader(), режимы ключей). Именно это позволяет форматонезависимому коду принимать CSV без спец-кейсов.

php
use avadim\FastExcelReader\Excel;

$book  = Excel::open('data.csv');          // вернёт Csv\CsvBook
$sheet = $book->sheet();                    // единственный лист CSV с именем "CSV"

$rows = $book->readRows();
// ключи — буквы столбцов Excel, ровно как для XLSX:
// [1 => ['A' => 'ID', 'B' => 'Name'], 2 => ['A' => '1', 'B' => 'John'], ...]

Формат определяется по сигнатуре файла, а не по расширению: OLE2-файл — это XLS, ZIP-файл — XLSX, всё остальное читается как текст с разделителями. Опции передаются вторым аргументом — в том числе любой параметр конфигурации и ['format' => 'csv'] для принудительного выбора CSV-ридера:

php
$book = Excel::open('data.txt', ['delimiter' => "\t", 'encoding' => 'Windows-1251']);
$book = Excel::open($file, ['format' => 'csv']); // принудительно CSV, независимо от сигнатуры

Поскольку детекция работает по исключению, не-табличный файл попадает в CSV-ридер. Бинарный ввод — NUL-байт или высокая доля управляющих символов — отсекается сразу понятной ошибкой, а не разбирается в мусор; текст UTF-16/UTF-32 при этом не затрагивается (его NUL-байты легитимны). Чтобы отключить эту проверку, задайте ['allow_binary' => true].

open() против openCsv(). Оба читают один и тот же файл; различаются тем, что возвращают, и ключами столбцов по умолчанию:

Excel::open($csv) Excel::openCsvReader($csv)
Возвращает Csv\CsvBook (объект файла) Csv\CsvReader (движок)
Ключи столбцов по умолчанию буквы Excel A, B, ... числа с нуля 0, 1, ...
API полный общий API AbstractSheet низкоуровневый API CsvReader

openCsv() не изменён и остаётся способом добраться до низкоуровневого движка (getCsvField(), getCsvLine(), onError(), setBufferSize(), ...). Из CsvBook тот же движок доступен через $book->getReader().

Чего у CSV нет. CSV не хранит форматов ячеек, поэтому нет ни автоматической типизации чисел/дат (любое значение — строка), ни стилей: readRowsWithStyles(), readCellStyles() и readStyles() возвращают пустые стили, а не бросают исключение; нет объединённых ячеек и изображений. Размер листа CSV тоже не хранит, поэтому dimension() пуст, пока вы явно не запросите фактический диапазон через actualDimension(), countRows() или countColumns() — они один раз сканируют файл (потоковый путь nextRow() этого не делает).

Продвинутое чтение

Чтение с заголовками

Если в CSV есть строка заголовков, можно использовать метод withHeader(), чтобы значения первой строки стали ключами для последующих строк.

php
$csv = Excel::openCsvReader($file);
$rows = $csv->withHeader()->nextRow();

foreach ($rows as $rowNum => $row) {
    // $row = ['ID' => '1', 'Name' => 'John', 'City' => 'New York']
    echo $row['Name'];
}

Имена столбцов можно задать и самостоятельно. Первая строка при этом всё равно пропускается, но имена берутся из вашего списка, а не из её значений. Имена применяются по порядку столбцов, поэтому буквы столбцов не нужны:

php
$rows = $csv->withHeader(['id', 'name', 'city'])->readRows();
// $row = ['id' => '1', 'name' => 'John', 'city' => 'New York']

Более короткий список переименует только те столбцы, которые он покрывает; остальные сохранят имя из строки заголовков.

Чтение через генератор (экономно по памяти)

Метод nextRow() возвращает \Generator, что идеально для обработки больших файлов без загрузки их целиком в память.

php
$csv = Excel::openCsvReader($file);
$generator = $csv->nextRow();

foreach ($generator as $row) {
    // Обработать каждую строку
}

Чтение в массив

Если файл небольшой и нужны все данные сразу:

php
$csv = Excel::openCsvReader($file);
$allRows = $csv->readRows();

Опции конфигурации

В openCsv() можно передать массив опций или объект CsvOptions.

php
use avadim\FastExcelReader\Csv\CsvOptions;

$options = [
    'delimiter' => ';',
    'enclosure' => '"',
    'encoding' => 'UTF-8',
    'trim_fields' => true,
    'skip_empty_lines' => true,
];

$csv = Excel::openCsvReader($file, $options);

// Другие способы задать опции:
$options = new CsvOptions($options)
    ->setDelimiter(';')
    ->setEnclosure('"')
    ->setEncoding('UTF-8')
    ->setTrimFields(true)
    ->setSkipEmptyLines(true)
;

$csv = Excel::openCsvReader($file, $options);

Доступные опции:

Опция Тип По умолч. Описание
mode string 'strict' Режим разбора: 'strict' или 'tolerant'
delimiter string null Разделитель колонок (например, ,, ;, \t). null или 'auto' — автоопределение.
enclosure string " Символ ограничителя поля.
encoding string null Кодировка входного файла. null — автоопределение.
double_quotes bool true Обрабатывать ли удвоенные кавычки как экранированные.
escape string '' Экранирующий символ (например, \).
trim_fields bool true Обрезать ли начальные/конечные пробелы у полей без кавычек.
skip_empty_lines bool true Пропускать ли пустые строки.
comment_prefix string null Символ(ы), обозначающие строку-комментарий (например, #).
allow_binary bool false Читать бинарно выглядящий ввод, а не отклонять его (обычно NUL-байт или много управляющих символов приводят к исключению).

Автоопределение разделителя

Если delimiter равен null или 'auto', ридер попытается определить разделитель, анализируя первые несколько строк файла.

Поддержка кодировок

Ридер автоматически определяет большинство распространённых кодировок, включая UTF-8, UTF-16 и различные региональные кодировки вроде Windows-1251 или Shift_JIS. Также можно вручную указать любую кодировку, поддерживаемую функцией PHP mb_convert_encoding.

Режимы разбора (строгий и толерантный)

  • Строгий режим ('strict'): выбрасывает ошибки, если CSV не строго следует RFC 4180 (например, если после закрывающей кавычки есть текст или внутри поля есть неэкранированные кавычки).
  • Толерантный режим ('tolerant'): пытается восстановиться и прочитать как можно больше данных при встрече с некорректной структурой CSV.

Обработка ошибок

Можно задать собственный обработчик ошибок для управления проблемами разбора, что особенно полезно в tolerant-режиме.

php
$csv = Excel::openCsvReader($file);
$csv->onError(function($code, $error, $line, $lineNo, $colNo) {
    echo "Error on line $lineNo, col $colNo: $error\n";
    echo "Line content: $line\n";
});

Примеры

Чтение файла с табуляцией (TSV)

php
$csv = Excel::openCsvReader('data.tsv', ['delimiter' => "\t"]);
foreach ($csv->nextRow() as $row) {
    // ...
}

Обработка файлов в кодировке Windows-1251

php
$csv = Excel::openCsvReader('russian_data.csv', ['encoding' => 'Windows-1251']);
foreach ($csv->nextRow() as $row) {
    // ...
}

Пропуск комментариев

php
$csv = Excel::openCsvReader('config.csv', ['comment_prefix' => '#']);
foreach ($csv->nextRow() as $row) {
    // Строки, начинающиеся с #, будут проигнорированы
}

Справочник API

FastExcelReader 4.5.0 · Поиск по текущей библиотеке и версии.

Загрузка поиска…

Не удалось загрузить поиск. Попробуйте ещё раз.

Ничего не найдено. Попробуйте другое слово или имя метода.