Чтение и запись CSV в Node.js: fs и fast-csv

CSV — простой текстовый формат для обмена данными. В Node.js вы можете читать и записывать CSV с помощью встроенного модуля fs или библиотек, таких как fast-csv. В этой инструкции показано: настройка проекта, чтение файла целиком и построчно, использование fast-csv для надёжного парсинга и запись CSV. Включены примеры, чеклисты, сценарии тестирования и рекомендации по выбору подхода.
Зачем это важно
CSV часто используют для экспорта данных из баз, обмена между приложениями и настройки. Неправильный парсинг CSV приводит к ошибкам: слияниям колонок, проблемам с кавычками и переполнению памяти при больших файлах. Поэтому полезно знать, когда использовать простые fs-методы, а когда — специализированные библиотеки.
Быстрая проверка окружения
Убедитесь, что Node.js установлен. Выполните:
node -vЕсли команда возвращает версию, можно продолжать.
Создайте каталог проекта и файл:
mkdir parse-csv
cd parse-csv
touch parseCSV.jsИспользование модуля fs
Модуль fs предоставляет низкоуровневые инструменты для работы с файлами. Он полезен, когда нужен простой и быстрый доступ без сторонних зависимостей.
Чтение всего файла целиком
readFile и readFileSync читают файл полностью. readFileSync блокирует выполнение, поэтому для больших файлов предпочитайте асинхронный readFile.
const fs = require('fs');
fs.readFile('csvdemo.csv', 'utf8', function (err, data) {
if (err) return console.error(err);
// простая обработка: разбить по строкам и по запятым
const rows = data.split('\n').map(r => r.split(','));
console.log(rows);
});Важно: этот подход потребляет память пропорционально размеру файла. Для больших CSV он не подходит.
Чтение построчно через поток
fs.createReadStream позволяет читать файл по частям. В связке с модулем readline вы получаете по одной строке за раз.
const fs = require('fs');
const readline = require('readline');
const stream = fs.createReadStream('./csvdemo.csv');
const rl = readline.createInterface({ input: stream });
let data = [];
rl.on('line', (row) => {
data.push(row.split(','));
});
rl.on('close', () => {
console.log(data);
});Этот метод экономит память, но простая разбивка по запятым не корректно обрабатывает кавычки, запятые внутри полей и переносы строк в полях. Для надёжного парсинга используйте специализированные библиотеки.
Использование fast-csv
fast-csv — популярная библиотека для парсинга и форматирования CSV. Она справляется со сложными случаями формата и поддерживает стримы.
Установка:
npm init -y
npm i fast-csvЧтение CSV с заголовками:
const fs = require('fs')
const csv = require('fast-csv');
const data = []
fs.createReadStream('./csvdemo.csv')
.pipe(csv.parse({ headers: true }))
.on('error', error => console.error(error))
.on('data', row => data.push(row))
.on('end', () => console.log(data));Параметры:
- headers: true — пропускает первую строку и возвращает объекты по именам колонок.
- headers: false — возвращает массивы для каждой строки.
Запись CSV с fast-csv
Пример записи массива объектов в CSV:
const fs = require('fs');
const csv = require('fast-csv');
const rows = [
{ name: 'Алиса', age: 30, city: 'Москва' },
{ name: 'Борис', age: 25, city: 'Санкт-Петербург' }
];
const ws = fs.createWriteStream('out.csv');
csv.write(rows, { headers: true }).pipe(ws);fast-csv корректно экранирует поля и обрабатывает нестандартные разделители.
Когда ручной парсинг не сработает
- Поля содержат запятые внутри кавычек.
- Внутри полей есть переносы строк.
- Используются разные разделители (точка с запятой, табуляция).
- Нужна потоковая обработка больших файлов с низким потреблением памяти.
В этих случаях библиотека типа fast-csv или csv-parser пригодится.
Альтернативы и сравнение
Три популярных подхода: встроенный fs, fast-csv и csv-parser. Ниже — краткая матрица сравнения.
| Подход | Простота | Надёжность парсинга | Поддержка стримов | Зависимости |
|---|---|---|---|---|
| fs (readFile) | высокая | низкая | нет | нет |
| fs + readline | средняя | низкая/средняя | да | нет |
| fast-csv | средняя | высокая | да | да |
| csv-parser | средняя | высокая | да | да |
Выберите fs для быстрых одноразовых задач и небольших файлов. Для продакшна и сложных CSV — fast-csv или csv-parser.
Практические рекомендации по производительности
- Для файлов >100 МБ используйте стримы и обработку по частям.
- Выделяйте буферы и не собирайте весь файл в массивы, если можно обрабатывать строки по мере поступления.
- Отключайте логирование в горячих циклах.
- При записи большого объёма данных используйте backpressure: следите за сигналом drain у потока записи.
Чеклист по ролям
Разработчик
- Проверить формат CSV (наличие заголовков, разделитель).
- Выбрать библиотеку и настроить опции (headers, delimiter, quote).
- Написать обработчики ошибок для stream error.
Инженер данных
- Подготовить схему колонок и примеры граничных значений.
- Обеспечить контроль целостности при разбиении/склеивании файлов.
Операции и безопасность
- Ограничить права на файлы с персональными данными.
- Внедрить процесс удаления временных файлов после обработки.
Критерии приёмки
- Парсер корректно обрабатывает поля с кавычками и запятыми внутри.
- Объём памяти не растёт пропорционально размеру файла при стримовой обработке.
- При наличии заголовков создаётся корректная структура объектов.
- При ошибке чтения/записи генерируется понятное сообщение и процесс не падает неконтролируемо.
Сценарии тестирования и примеры тест-кейсов
- Малый CSV без кавычек — чтение возвращает ожидаемый массив.
- CSV с полем, содержащим запятые в кавычках — поле читается как единое значение.
- CSV с переносом строки в поле — парсер корректно собирает многострочное поле.
- Большой CSV (симуляция) — приложение не превышает заданный предел памяти.
- Неправильный формат CSV — парсер возвращает ошибку и логгирует строку с проблемой.
Частые ошибки и как их избежать
- Ожидание заголовков, когда их нет. Решение: проверяйте первую строку или сделайте headers опциональным.
- Разные разделители. Решение: сначала определить разделитель (сканировать первые несколько строк).
- Игнорирование кодировки файла. Решение: явно указывать ‘utf8’ или нужную кодировку в createReadStream/readFile.
Важно: никогда не парсите CSV «на глаз» в продакшене. Используйте проверенные библиотеки для сложных данных.
Короткая методика выбора
- Небольшой файл и простая структура -> fs.readFile.
- Большой файл или поток данных -> fs.createReadStream + библиотека для парсинга.
- Сложные поля (кавычки, переносы, разные разделители) -> fast-csv или csv-parser.
1‑строчная глоссарий
CSV — Comma-Separated Values, текстовый формат хранения табличных данных, где поля разделяются запятыми или другим символом-разделителем.
Советы по локали и разделителю
В некоторых регионах (например, в Европe) по умолчанию используют точку с запятой (;) в качестве разделителя. Если вы обмениваетесь файлами между приложениями в разных странах, явно указывайте разделитель и кодировку.
Пример playbook для задачи «импорт CSV в базу»
- Валидация: проверить заголовки и кодировку.
- Трансформация: маппинг колонок и приведение типов.
- Загрузка: вставлять батчами, контролируя размер транзакций.
- Отчётность: логировать количество обработанных и пропущенных строк.
- Очистка: удалить временные файлы.
Заключение
fs подходит для простых случаев. Для надёжного парсинга и записи сложных CSV используйте fast-csv или csv-parser. Выбирайте стримы для больших файлов, следите за потреблением памяти и тестируйте на граничных случаях.
Краткие выводы:
- Не парсите CSV вручную для продакшена.
- Используйте стримы для больших данных.
- Протестируйте поведение при кавычках и переносах строк.
Похожие материалы
Как просмотреть и извлечь содержимое JAR‑файла
Оптимизация энергопотребления в Windows 11
Безопасный режим Mozilla Firefox — как и зачем
Остановить обновление Windows 10 до версии
Исправить «Не удалось найти IP-адрес сервера» в Chrome