Введение: Зачем уметь работать с файлами в JavaScript?
Когда мы говорим о JavaScript, большинство сразу вспоминает браузер и интерактивные интерфейсы. Однако с появлением платформы Node.js JavaScript вышел далеко за пределы веб-страниц. Сегодня это полноценный язык для серверной разработки, автоматизации и утилит. И одна из ключевых задач, с которой сталкивается каждый разработчик — это работа с файловой системой.
Умение читать, записывать, перемещать и удалять файлы — это база, без которой невозможно представить ни один серьёзный проект. Будь то логгер, конфигурационный файл, загрузка изображений или анализ данных — везде нужен доступ к файловой системе.
В этой статье мы разберём практические примеры работы с файловой системой в Node.js. Вы узнаете, как использовать встроенный модуль fs, какие существуют методы и как избежать типичных ошибок. Весь код можно сразу запускать и тестировать.
Основные методы модуля fs
Модуль fs (File System) входит в стандартную поставку Node.js. Его не нужно устанавливать отдельно. Для начала работы достаточно подключить его в начале файла:
const fs = require('fs');
const fsPromises = require('fs').promises; // для работы с промисами
Все методы модуля fs существуют в трёх вариантах:
- Синхронные — блокируют выполнение кода до завершения операции. Обычно имеют суффикс
Sync. - Асинхронные с колбэками — классический стиль Node.js.
- Асинхронные на промисах — современный подход через
fs.promises.
В современных проектах рекомендуется использовать промисы и async/await. Это делает код чище и понятнее.
Чтение файлов
Самый частый сценарий — прочитать содержимое файла. Рассмотрим пример с текстовым файлом data.txt:
const fs = require('fs').promises;
async function readFileExample() {
try {
const data = await fs.readFile('data.txt', 'utf8');
console.log('Содержимое файла:');
console.log(data);
} catch (err) {
console.error('Ошибка чтения файла:', err.message);
}
}
readFileExample();
Второй параметр 'utf8' указывает кодировку. Если его опустить, вы получите сырой буфер (Buffer). Для текстовых файлов всегда указывайте кодировку.
Запись в файл
Запись данных в файл может выполняться двумя способами: полная перезапись или добавление в конец.
Перезапись файла:
const fs = require('fs').promises;
async function writeFileExample() {
try {
await fs.writeFile('output.txt', 'Привет, файловая система!');
console.log('Файл успешно записан');
} catch (err) {
console.error('Ошибка записи:', err.message);
}
}
writeFileExample();
Добавление в конец файла:
const fs = require('fs').promises;
async function appendFileExample() {
try {
await fs.appendFile('log.txt', `Новая запись: ${new Date().toISOString()}\n`);
console.log('Данные добавлены');
} catch (err) {
console.error('Ошибка добавления:', err.message);
}
}
appendFileExample();
Метод appendFile идеально подходит для ведения логов или накопления данных.
Управление директориями и файлами
Работа с файловой системой не ограничивается чтением и записью. Часто требуется создавать папки, проверять существование файлов или удалять их.
Создание и удаление директорий
const fs = require('fs').promises;
async function manageDirectories() {
try {
// Создание директории (если её нет)
await fs.mkdir('myFolder', { recursive: true });
console.log('Папка создана');
// Удаление пустой директории
await fs.rmdir('myFolder');
console.log('Папка удалена');
} catch (err) {
console.error('Ошибка:', err.message);
}
}
manageDirectories();
Опция { recursive: true } позволяет создавать вложенные папки, например ./a/b/c, не беспокоясь о том, что родительские папки не существуют.
Проверка существования файла или папки
const fs = require('fs').promises;
async function checkExists() {
try {
await fs.access('myFile.txt');
console.log('Файл существует');
} catch {
console.log('Файл не найден');
}
}
checkExists();
Метод access не возвращает содержимого, а только проверяет доступность пути. Это быстрый способ узнать, существует ли файл или папка.
Копирование и перемещение файлов
const fs = require('fs').promises;
async function copyAndMove() {
try {
// Копирование
await fs.copyFile('source.txt', 'destination.txt');
console.log('Файл скопирован');
// Переименование (перемещение)
await fs.rename('oldName.txt', 'newName.txt');
console.log('Файл переименован');
} catch (err) {
console.error('Ошибка:', err.message);
}
}
copyAndMove();
Метод rename работает и как перемещение между папками: fs.rename('./folder/file.txt', './other/file.txt').
Практический пример: утилита для логирования
Давайте соберём всё вместе и создадим простую, но полезную утилиту для записи логов с автоматической ротацией по дням.
const fs = require('fs').promises;
const path = require('path');
class Logger {
constructor(logDir = 'logs') {
this.logDir = logDir;
}
async init() {
await fs.mkdir(this.logDir, { recursive: true });
}
getLogFileName() {
const today = new Date().toISOString().slice(0, 10); // '2025-04-08'
return path.join(this.logDir, `log-${today}.txt`);
}
async log(level, message) {
const timestamp = new Date().toISOString();
const logLine = `[${timestamp}] [${level.toUpperCase()}] ${message}\n`;
try {
await fs.appendFile(this.getLogFileName