Работа с файловой системой в JavaScript на Node.js: полное руководство

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: почему работа с файловой системой важна в Node.js

В современной веб-разработке редко можно обойтись без взаимодействия с файловой системой. Будь то загрузка аватаров пользователей, генерация логов, обработка CSV-отчетов или чтение конфигурационных файлов — Node.js предоставляет мощный встроенный модуль fs (File System) для этих задач.

В отличие от браузерного JavaScript, где доступ к файлам жестко ограничен в целях безопасности, Node.js дает полный контроль над файловой системой сервера. В этой статье мы разберем ключевые операции на практических примерах, которые помогут вам уверенно работать с файлами и папками.

Что вы узнаете:

  • Как читать и записывать файлы (синхронно и асинхронно)
  • Как работать с потоками (Streams) для больших файлов
  • Как создавать, переименовывать и удалять папки
  • Как правильно обрабатывать ошибки и пути

1. Основы: чтение и запись файлов

Модуль fs предлагает три основных подхода к работе с файлами: синхронный, асинхронный (с колбэками) и на промисах. Рекомендуется использовать асинхронный подход на промисах (fs.promises) — он не блокирует Event Loop и удобнее для чтения.

1.1 Чтение файла

Самый простой способ прочитать файл целиком — использовать readFile.

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

async function readConfig() {
  try {
    const data = await fs.readFile('./config.json', 'utf-8');
    const config = JSON.parse(data);
    console.log('Порт:', config.port);
  } catch (err) {
    console.error('Ошибка чтения:', err.message);
  }
}

readConfig();

Важно: Указывайте кодировку ('utf-8'), иначе вернется объект Buffer.

1.2 Запись в файл

Для записи используйте writeFile (перезаписывает файл) или appendFile (добавляет в конец).

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

async function saveLog(message) {
  const logLine = `[${new Date().toISOString()}] ${message}\n`;
  try {
    await fs.appendFile('./app.log', logLine);
    console.log('Лог сохранен');
  } catch (err) {
    console.error('Ошибка записи:', err);
  }
}

saveLog('Сервер запущен');

2. Работа с большими файлами: Streams (потоки)

Представьте, что вам нужно прочитать файл размером 2 ГБ. Метод readFile загрузит его целиком в оперативную память, что может привести к утечке памяти. Для таких случаев существуют потоки (fs.createReadStream и fs.createWriteStream).

Поток обрабатывает данные частями (чанками), не храня весь файл в памяти.

Пример: копирование большого файла

const fs = require('fs');
const path = require('path');

const source = path.join(__dirname, 'bigfile.zip');
const destination = path.join(__dirname, 'copy.zip');

const readStream = fs.createReadStream(source);
const writeStream = fs.createWriteStream(destination);

readStream.on('data', (chunk) => {
  console.log(`Прочитано ${chunk.length} байт`);
  writeStream.write(chunk);
});

readStream.on('end', () => {
  writeStream.end();
  console.log('Копирование завершено');
});

readStream.on('error', (err) => {
  console.error('Ошибка чтения:', err);
});

Совет: Для копирования удобнее использовать встроенный метод pipeline из модуля stream — он автоматически обрабатывает ошибки и закрывает потоки.

3. Управление директориями

Работа с папками — не менее важная часть. Node.js позволяет создавать, читать и удалять директории.

3.1 Создание и проверка папки

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

async function ensureDir(dirPath) {
  try {
    await fs.mkdir(dirPath, { recursive: true });
    console.log(`Папка "${dirPath}" создана или уже существует`);
  } catch (err) {
    if (err.code === 'EEXIST') {
      console.log('Папка уже существует');
    } else {
      console.error('Ошибка:', err);
    }
  }
}

ensureDir('./uploads/images');

Опция { recursive: true } позволяет создавать вложенные папки (например, a/b/c), если родительские не существуют.

3.2 Чтение содержимого папки

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

async function listFiles(dirPath) {
  try {
    const files = await fs.readdir(dirPath);
    console.log('Содержимое папки:');
    files.forEach(file => console.log(` - ${file}`));
  } catch (err) {
    console.error('Ошибка чтения папки:', err);
  }
}

listFiles('./uploads');

3.3 Удаление папки с содержимым

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

async function removeDir(dirPath) {
  try {
    await fs.rm(dirPath, { recursive: true, force: true });
    console.log(`Папка "${dirPath}" удалена`);
  } catch (err) {
    console.error('Ошибка удаления:', err);
  }
}

removeDir('./temp');

Метод rm (доступен с Node.js 14.14) — самый современный способ удалить папку со всем содержимым.

4. Практический пример: сборщик логов

Давайте объединим полученные знания в небольшой утилите, которая читает все .log файлы из папки, фильтрует ошибки и записывает их в отдельный файл.

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

async function collectErrors(logsDir, outputFile) {
  try {
    const files = await fs.readdir(logsDir);
    const errors = [];

    for (const file of files) {
      if (path.extname(file) !== '.log') continue;

      const filePath = path.join(logsDir, file);
      const content = await fs.readFile(filePath, 'utf-8');
      const lines = content.split('\n');

      lines.forEach((line, index) => {
        if (line.toLowerCase().includes('error')) {
          errors.push(`[${file}:${index + 1}] ${line}`);
        }
      });
    }

    if (errors.length > 0                

Блоги

Рекомендаций по книгам