← Назад к вопросам
В чем разница между readFile и readStream?
1.7 Middle🔥 151 комментариев
#Node.js и JavaScript#Кэширование и производительность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
В чем разница между readFile и readStream
Краткий ответ
readFile загружает весь файл в память, а readStream читает файл по частям (chunks). readFile проще, но неэффективен для больших файлов. readStream экономит память, но требует обработки событий.
readFile — весь файл в память
const fs = require('fs');
// Асинхронная версия
fs.readFile('./large-file.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log(data); // Весь файл в памяти
});
// Promise версия
const fs = require('fs').promises;
const data = await fs.readFile('./file.txt', 'utf8');
console.log(data);
Характеристики:
- Весь файл загружается в памяти
- Просто в использовании
- Блокирует выполнение (асинхронно, но весь файл ждёт)
- Подходит для маленьких файлов
- Высокое потребление RAM для больших файлов
readFile поток загрузки:
┌─────────────┐
│ Start │
│ Loading │
│ Entire File │ ← весь файл в RAM
│ Ready │
└─────────────┘
(1 callback)
readStream — читаем частями
const fs = require('fs');
const stream = fs.createReadStream('./large-file.txt', {
encoding: 'utf8',
highWaterMark: 16 * 1024 // 16 KB за раз (по умолчанию)
});
stream.on('data', (chunk) => {
console.log('Received chunk:', chunk.length, 'bytes');
});
stream.on('end', () => {
console.log('File reading complete');
});
stream.on('error', (err) => {
console.error('Stream error:', err);
});
Характеристики:
- Читает файл по частям (chunks)
- Экономит память
- События: data, end, error, close
- Подходит для больших файлов
- Немного сложнее в использовании
readStream поток загрузки:
┌─────┬─────┬─────┬─────┬─────┐
│Ch 1 │Ch 2 │Ch 3 │Ch 4 │Ch 5 │ ← chunks в буфере
└─────┴─────┴─────┴─────┴─────┘
(много data событий)
Сравнение использования памяти
// Файл 1 GB
// ❌ readFile — RAM spike до 1 GB
fs.readFile('./1gb-file.bin', (err, data) => {
// Память: +1 GB
process(data);
// Память: -1 GB (после сборки мусора)
});
// ✅ readStream — RAM spike только ~16 KB
fs.createReadStream('./1gb-file.bin')
.on('data', (chunk) => {
// Память: +16 KB
process(chunk);
// Память: -16 KB (следующий chunk заменит этот)
});
Практические примеры
1. Отправка файла клиенту (Express)
// ❌ Плохо — readFile
app.get('/download', (req, res) => {
fs.readFile('./large-file.zip', (err, data) => {
res.send(data); // Весь файл в памяти
});
});
// ✅ Хорошо — pipe
app.get('/download', (req, res) => {
fs.createReadStream('./large-file.zip')
.pipe(res); // Стриминг напрямую
});
2. Обработка логов
const readline = require('readline');
const fs = require('fs');
const rl = readline.createInterface({
input: fs.createReadStream('./huge-log.txt'),
crlfDelay: Infinity
});
rl.on('line', (line) => {
if (line.includes('ERROR')) {
console.log(line);
}
});
rl.on('close', () => {
console.log('Log processed');
});
3. Копирование файла
// ❌ readFile — неэффективно
fs.readFile('./source.bin', (err, data) => {
fs.writeFile('./dest.bin', data, (err) => {
console.log('Done');
});
});
// ✅ readStream + writeStream — оптимально
fs.createReadStream('./source.bin')
.pipe(fs.createWriteStream('./dest.bin'))
.on('close', () => {
console.log('Copied');
});
4. Стриминг видео/музыки
app.get('/video/:id', (req, res) => {
const filePath = `./videos/${req.params.id}.mp4`;
const stat = fs.statSync(filePath);
const fileSize = stat.size;
const range = req.headers.range;
if (range) {
const parts = range.replace(/bytes=/, '').split('-');
const start = parseInt(parts[0], 10);
const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;
const chunksize = end - start + 1;
res.writeHead(206, {
'Content-Range': `bytes ${start}-${end}/${fileSize}`,
'Accept-Ranges': 'bytes',
'Content-Length': chunksize,
'Content-Type': 'video/mp4'
});
fs.createReadStream(filePath, { start, end })
.pipe(res);
} else {
res.writeHead(200, {
'Content-Length': fileSize,
'Content-Type': 'video/mp4'
});
fs.createReadStream(filePath).pipe(res);
}
});
5. Обработка CSV (transform stream)
const { Transform } = require('stream');
const csv = require('csv-parser');
fs.createReadStream('./data.csv')
.pipe(csv())
.on('data', (row) => {
console.log('Processing row:', row);
})
.on('end', () => {
console.log('CSV processing complete');
});
Когда использовать
readFile:
- Маленькие текстовые файлы (< 10 MB)
- Конфигурационные файлы
- JSON/YAML
- Когда нужен весь контент сразу
readStream:
- Большие файлы (> 100 MB)
- Стриминг (видео, аудио)
- Обработка логов
- Real-time обработка
- Передача файлов по сети
Вывод
- readFile — прост, но опасен для больших файлов
- readStream — экономит память, лучше для production
- pipe() — красивый способ соединить read и write потоки
- Для большинства production задач используй streams