Файловые потоки

Тема дорожной карты · Node.js

Файловые потоки в Node.js позволяют читать или записывать большие файлы порциями, а не загружать весь файл в память сразу, что делает их незаменимыми для построения память-эффективных серверных сервисов, обрабатывающих загрузки, выгрузки файлов, обработку логов или конвейеры преобразования данных. Функции fs.createReadStream() и fs.createWriteStream() возвращают объекты потоков Node.js Readable и Writable соответственно, которые генерируют события data, end и error и полностью участвуют в протоколе backpressure потоков Node.js. Файловые потоки легко интегрируются с другими потоками Node.js через stream.pipeline() — например, pipeline(fs.createReadStream('input.csv'), transformStream, fs.createWriteStream('output.json'), callback) обрабатывает преобразование файла без буферизации всего набора данных. Параметр highWaterMark у обеих функций — createReadStream() и createWriteStream() — управляет размером внутреннего буфера, позволяя разработчикам настраивать баланс между потреблением памяти и пропускной способностью для конкретных рабочих нагрузок серверных приложений Node.js. При построении эндпоинтов скачивания файлов в Express.js передача fs.createReadStream() напрямую в HTTP-объект res значительно эффективнее, чем чтение всего файла через fs.readFile() перед отправкой.

Как это работает

Файловые потоки в Node — это unix-pipe-подобные абстракции для инкрементальных данных: Readable, Writable, Duplex, Transform. Используйте, когда данные большие (GB-файлы, сетевые загрузки) или бесконечные (логи, websockets). Современный Node поддерживает stream/promises и pipeline() для безопасной композиции с обработкой ошибок и cleanup. Web Streams API (ReadableStream, WritableStream) доступен с Node 18 — тот же shape, что в браузере.

Когда применять

Streams — когда payload может превысить RAM: загрузки файлов, большие выборки из БД, CSV-импорт. pipeline() (не сырой .pipe()) — чтобы ошибки пробрасывались, ресурсы закрывались. Для HTTP-ответов можно return res.pipe(stream) — forward без буферизации. Пропустите streams для маленьких in-memory данных — overhead API больше выгоды; берите buffer или string.

Типичные ошибки

Ловушки Файловые потоки: забытый backpressure (медленный consumer, быстрый producer = раздутая память); .pipe() без error-обработчиков (тихий провал); смешение object-mode и binary-mode streams; конверсия stream → Buffer ради JSON.parse (теряет смысл). for await (const chunk of stream) в современном Node — читается чище, чем event-обработчики.

Связанные понятия

Полезные ресурсы