Какие функции для чтения файлов есть в модуле fs в Node.js?

Ответ

Модуль fs в Node.js предоставляет несколько подходов к чтению файлов, каждый для своих сценариев.

1. Асинхронное чтение (неблокирующее, рекомендуется)

  • fs.readFile(path[, options], callback) — классический асинхронный метод с колбэком. Читает весь файл в память.
  • fsPromises.readFile(path[, options]) — современная Promise-версия того же метода. Я предпочитаю её из-за удобства использования с async/await.

2. Синхронное чтение (блокирующее)

  • fs.readFileSync(path[, options]) — синхронная версия. Блокирует цикл событий до завершения чтения. Использую её только в скриптах инициализации или CLI-утилитах, где простота важнее производительности.

3. Потоковое чтение (для больших файлов)

  • fs.createReadStream(path[, options]) — создает читаемый поток. Это ключевой метод для обработки файлов, которые не помещаются в память (например, логи, видео, большие дампы). Поток читает данные чанками, что экономит память.

Примеры использования:

const fs = require('fs');
const fsPromises = require('fs').promises;

// 1. Асинхронно с колбэком (устаревший, но встречается в легаси-коде)
fs.readFile('./config.json', 'utf8', (err, data) => {
  if (err) throw err;
  console.log('Конфиг загружен:', JSON.parse(data));
});

// 2. Асинхронно с Promises (современный стандарт)
async function loadConfig() {
  try {
    const data = await fsPromises.readFile('./config.json', 'utf8');
    return JSON.parse(data);
  } catch (err) {
    console.error('Ошибка чтения файла:', err);
  }
}

// 3. Синхронно (для инициализации)
const packageJson = fs.readFileSync('./package.json', 'utf8');
console.log('Версия приложения:', JSON.parse(packageJson).version);

// 4. Потоковое чтение большого файла
const readStream = fs.createReadStream('./huge-logfile.log', 'utf8');
let lineCount = 0;

readStream.on('data', (chunk) => {
  lineCount += (chunk.match(/n/g) || []).length;
});

readStream.on('end', () => {
  console.log(`Файл содержит примерно ${lineCount} строк.`);
});

Почему важен выбор? readFile прост для маленьких файлов, но createReadStream критически важен для масштабируемости и низкого потребления памяти при работе с большими данными.

Ответ 18+ 🔞

Слушай, давай разберем эту тему про чтение файлов в Node.js, а то тут, бля, вариантов — овердохуища, и если выбрать не тот, можно такую дичь накодить, что потом сам от себя охуеешь.

Вот модуль fs — он как швейцарский нож, только для файлов. И у него есть три основных подхода, каждый для своих граблей.

1. Асинхронное чтение (нормальный, неблокирующий путь)

  • fs.readFile(path[, options], callback) — это классика жанра, старый добрый способ с колбэком. Он читает весь файл целиком и потом отдаёт тебе. Просто, но для здоровенных файлов — пиздец как память жрёт.
  • fsPromises.readFile(path[, options]) — а это уже его крутой младший брат, который работает с промисами. Я его обожаю, потому что с async/await это просто песня, а не код. Рекомендую.

2. Синхронное чтение (блокирующее, для особых случаев)

  • fs.readFileSync(path[, options]) — вот это штука тормозит весь твой сервак, пока файл не прочитает. Выглядит как хитрая жопа, которая упрощает код, но используй её только в скриптах для инициализации или в CLI-утилитах, где производительность — да похуй. В веб-сервере так делать — самоубийство.

3. Потоковое чтение (для файлов-гигантов)

  • fs.createReadStream(path[, options]) — а вот это, дружок, мастхэв. Создает читаемый поток. Если файл размером с твою совесть (логи, видео, дампы баз), то это твой выбор. Он не пытается заглотить всё сразу, а жуёт по кусочкам (чанкам), и память не ебёт. Красота.

Смотри, как это выглядит в коде:

const fs = require('fs');
const fsPromises = require('fs').promises;

// 1. Асинхронно с колбэком (старьё, но в легаси ещё живёт)
fs.readFile('./config.json', 'utf8', (err, data) => {
  if (err) throw err;
  console.log('Конфиг загружен:', JSON.parse(data));
});

// 2. Асинхронно с Промисами (современно, модно, молодёжно)
async function loadConfig() {
  try {
    const data = await fsPromises.readFile('./config.json', 'utf8');
    return JSON.parse(data);
  } catch (err) {
    console.error('Ошибка чтения файла:', err); // э сабака сука
  }
}

// 3. Синхронно (когда нужно быстро и чётко, и похуй на блокировку)
const packageJson = fs.readFileSync('./package.json', 'utf8');
console.log('Версия приложения:', JSON.parse(packageJson).version);

// 4. Потоковое чтение (когда файл больше, чем твои амбиции)
const readStream = fs.createReadStream('./huge-logfile.log', 'utf8');
let lineCount = 0;

readStream.on('data', (chunk) => {
  lineCount += (chunk.match(/n/g) || []).length;
});

readStream.on('end', () => {
  console.log(`Файл содержит примерно ${lineCount} строк.`); // ни хуя себе
});

А теперь, ёпта, главное: readFile — это как взять стакан и выпить. Для стакана воды — ок. createReadStream — это как пить из шланга, когда на тебя несётся пожарная цистерна. Для больших данных — только так, иначе твое приложение накроется медным тазом. Выбирай с умом, чувак.