Работа с файловой системой в Node.js: полное руководство
В современной веб-разработке умение эффективно работать с файловой системой — один из ключевых навыков backend-разработчика. Node.js предоставляет мощный и гибкий модуль fs (File System), который позволяет выполнять все основные операции с файлами и директориями: чтение, запись, удаление, переименование и многое другое. В этой статье мы подробно разберем, как работать с файловой системой в Node.js, рассмотрим синхронные и асинхронные методы, а также изучим работу с путями.
Подключение модуля fs и основные принципы
Для начала работы с файловой системой в Node.js необходимо подключить встроенный модуль fs. Это делается одной строкой кода:
const fs = require('fs');
Модуль fs предоставляет как синхронные, так и асинхронные методы. Асинхронные методы, как правило, принимают callback-функцию в качестве последнего аргумента и являются предпочтительными для production-кода, так как не блокируют event loop. Синхронные методы оканчиваются на Sync и могут быть полезны при инициализации приложения или в скриптах.
Кроме того, начиная с Node.js 10, доступна работа с fs/promises — версия методов, возвращающих промисы:
const fs = require('fs/promises');
В этой статье мы будем использовать преимущественно асинхронный подход с промисами, так как он наиболее современный и удобный.
Чтение файлов в Node.js
Чтение файлов — одна из самых частых операций. Рассмотрим три основных способа.
Чтение всего файла целиком (асинхронно)
Метод fs.readFile() читает содержимое файла полностью в память. Это удобно для небольших файлов.
const fs = require('fs/promises');
async function readFileExample() {
try {
const data = await fs.readFile('example.txt', 'utf8');
console.log('Содержимое файла:', data);
} catch (err) {
console.error('Ошибка при чтении файла:', err);
}
}
readFileExample();
Чтение файла построчно (потоковое чтение)
Для больших файлов лучше использовать потоки (streams) или читать файл построчно с помощью readline:
const fs = require('fs');
const readline = require('readline');
async function readFileLineByLine() {
const fileStream = fs.createReadStream('large-file.txt');
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
for await (const line of rl) {
console.log('Строка:', line);
}
}
readFileLineByLine();
Синхронное чтение
Если вам нужно прочитать файл прямо сейчас и вы готовы заблокировать выполнение:
const fs = require('fs');
try {
const data = fs.readFileSync('example.txt', 'utf8');
console.log(data);
} catch (err) {
console.error(err);
}
Запись и обновление файлов
Node.js предоставляет несколько методов для записи данных в файлы.
Запись в файл (перезапись)
Метод fs.writeFile() создает новый файл или перезаписывает существующий:
const fs = require('fs/promises');
async function writeFileExample() {
try {
await fs.writeFile('output.txt', 'Привет, мир!', 'utf8');
console.log('Файл успешно записан');
} catch (err) {
console.error('Ошибка записи:', err);
}
}
writeFileExample();
Добавление данных в конец файла
Если нужно добавить данные, не удаляя существующие, используйте fs.appendFile():
const fs = require('fs/promises');
async function appendToFile() {
try {
await fs.appendFile('log.txt', `Новая запись: ${new Date()}\n`);
console.log('Данные добавлены');
} catch (err) {
console.error('Ошибка:', err);
}
}
appendToFile();
Работа с потоками для больших данных
Для записи больших объемов данных используйте fs.createWriteStream():
const fs = require('fs');
const writeStream = fs.createWriteStream('big-file.txt');
for (let i = 0; i < 1000000; i++) {
writeStream.write(`Строка номер ${i}\n`);
}
writeStream.end();
Управление директориями и файлами
Помимо чтения и записи, часто требуется создавать, удалять и перемещать файлы и папки.
Создание директорий
Метод fs.mkdir() создает новую папку. Опция recursive: true позволяет создавать вложенные директории:
const fs = require('fs/promises');
async function createDirectories() {
try {
await fs.mkdir('project/src/components', { recursive: true });
console.log('Директории созданы');
} catch (err) {
console.error('Ошибка:', err);
}
}
createDirectories();
Удаление файлов и папок
Для удаления файла используйте fs.unlink(), для пустой директории — fs.rmdir(). Для удаления папки со всем содержимым — fs.rm() с опцией recursive: true:
const fs = require('fs/promises');
async function deleteExample() {
try {
await fs.unlink('temp-file.txt');
console.log('Файл удален');
// Удаление папки со всем содержимым
await fs.rm('temp-folder', { recursive: true, force: true });
console.log('Папка удалена');
} catch (err) {
console.error('Ошибка удаления:', err);
}
}
deleteExample();
Переименование и перемещение
Метод fs.rename() позволяет переименовать или переместить файл/папку:
const fs = require('fs/promises');
async function moveFile() {
try {
await fs.rename('source.txt', 'backup/source.txt');
console.log('Файл перемещен');
} catch (err) {
console.error('Ошибка:', err);
}
}
moveFile();
Работа с путями с помощью модуля path
Модуль path — незаменимый помощник