Работа с файловой системой в JavaScript (Node.js)
В современной веб-разработке JavaScript давно вышел за пределы браузера. Благодаря платформе Node.js разработчики получили возможность создавать серверные приложения, работать с базами данных и, конечно, взаимодействовать с файловой системой. Умение читать, записывать, удалять и перемещать файлы — один из ключевых навыков любого backend-разработчика. В этой статье мы подробно разберём, как работать с файловой системой в JavaScript на Node.js, используя встроенный модуль fs и его современную промисную версию fs/promises.
Материал будет полезен как новичкам, только начинающим изучать Node.js, так и опытным разработчикам, желающим систематизировать знания. Все примеры кода можно запустить в вашей среде разработки.
Подключение модуля fs и основные методы
Для работы с файловой системой в Node.js используется встроенный модуль fs (file system). Его не нужно устанавливать отдельно — он доступен сразу после установки Node.js. Подключается он стандартным способом:
const fs = require('fs');
Однако в современном JavaScript (ES6+) и Node.js (начиная с версии 14) рекомендуется использовать синтаксис ES modules и работать с промисной версией fs/promises. Это позволяет избежать "callback hell" и писать более чистый, асинхронный код с помощью async/await.
import * as fs from 'fs/promises';
// или
const fs = require('fs/promises');
Основные методы модуля fs делятся на три категории:
- Синхронные — блокируют поток выполнения (например,
fs.readFileSync()). Используются редко, в основном в скриптах инициализации. - Асинхронные с колбэками — традиционный стиль Node.js (например,
fs.readFile()). - Асинхронные на промисах — современный стиль (
fs/promises). Рекомендуется для большинства задач.
Чтение файлов в Node.js
Начнём с самого распространённого действия — чтения содержимого файла. Рассмотрим два подхода: с использованием колбэков и с использованием промисов.
Чтение через колбэки (традиционный способ)
const fs = require('fs');
fs.readFile('example.txt', 'utf8', (err, data) => {
if (err) {
console.error('Ошибка чтения файла:', err);
return;
}
console.log('Содержимое файла:', data);
});
Обратите внимание: мы передаём кодировку 'utf8' вторым аргументом. Если её не указать, данные вернутся в виде бинарного буфера (Buffer).
Чтение через промисы (рекомендуемый способ)
import { readFile } from 'fs/promises';
async function readExample() {
try {
const data = await readFile('example.txt', 'utf8');
console.log('Содержимое файла:', data);
} catch (err) {
console.error('Ошибка чтения файла:', err);
}
}
readExample();
Код стал чище и понятнее. Ошибки обрабатываются через try/catch, что привычно для разработчиков, знакомых с другими языками.
Запись данных в файл
Запись в файл — вторая по важности операция. В Node.js есть два основных метода: writeFile (перезаписывает файл) и appendFile (добавляет данные в конец файла).
Перезапись файла
import { writeFile } from 'fs/promises';
async function writeExample() {
try {
await writeFile('output.txt', 'Привет, мир!', 'utf8');
console.log('Файл успешно записан');
} catch (err) {
console.error('Ошибка записи:', err);
}
}
writeExample();
Если файл output.txt не существует, он будет создан автоматически. Если существует — его содержимое будет полностью перезаписано.
Добавление данных в конец файла
import { appendFile } from 'fs/promises';
async function appendExample() {
try {
await appendFile('log.txt', `Новая запись: ${new Date().toISOString()}\n`);
console.log('Данные добавлены');
} catch (err) {
console.error('Ошибка добавления:', err);
}
}
appendExample();
Метод appendFile идеально подходит для ведения логов или накопления данных.
Работа с директориями и метаданными
Файловая система — это не только файлы, но и папки. Рассмотрим основные операции с директориями.
Создание папок
import { mkdir } from 'fs/promises';
async function createDir() {
try {
await mkdir('new_folder', { recursive: true });
console.log('Папка создана');
} catch (err) {
console.error('Ошибка создания папки:', err);
}
}
createDir();
Опция { recursive: true } позволяет создавать вложенные директории одной командой (например, ./a/b/c).
Чтение содержимого папки
import { readdir } from 'fs/promises';
async function listDir(dirPath = '.') {
try {
const files = await readdir(dirPath);
console.log('Содержимое папки:', files);
} catch (err) {
console.error('Ошибка чтения папки:', err);
}
}
listDir('./my_folder');
Метод возвращает массив строк — имён файлов и папок внутри указанной директории. Если нужно получить полную информацию (размер, дата создания, права доступа), используйте readdir с опцией { withFileTypes: true }.
Получение информации о файле или папке
import { stat } from 'fs/promises';
async function getFileInfo(filePath) {
try {
const stats = await stat(filePath);
console.log('Размер:', stats.size, 'байт');
console.log('Это файл?', stats.isFile());
console.log('Это папка?', stats.isDirectory());
console.log('Дата создания:', stats.birthtime);
} catch (err) {
console.error('Ошибка получения информации:', err);
}
}
getFileInfo('example.txt');