Модуль fs.promises в Node.js

Модуль 4: Node.js, Next.js и Angular
3 уровень , 5 лекция
Открыта

1. Исторический экскурс

Когда-то в Node.js для работы с файлами был только модуль fs (File System), и все асинхронные методы работали через колбэки:

const fs = require('fs');

fs.readFile('data.txt', 'utf-8', (err, data) => {
    if (err) {
        console.error('Ошибка чтения файла:', err);
        return;
    }
    console.log('Содержимое файла:', data);
});

Это работало, но с ростом сложности кода появлялись вложенные колбэки, от которых хотелось сбежать на край света.

С появлением промисов и синтаксиса async/await жизнь стала проще. Но чтобы использовать промисы с файловой системой, приходилось либо вручную оборачивать методы в промисы, либо использовать сторонние библиотеки.

Начиная с Node.js 10, появился модуль fs.promises, который содержит все основные методы для работы с файлами, но возвращает промисы, а не требует колбэков.

Почему это удобно?

  • Код становится плоским и читаемым (никаких "лесенок" из колбэков).
  • Можно использовать async/await, а значит — писать асинхронный код почти как синхронный.
  • Современный подход, который рекомендуется использовать во всех новых проектах.

Как подключить и использовать fs.promises

В Node.js модуль fs.promises — это специальное свойство у стандартного fs. Для импорта используйте:

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

Или, если вы используете ES-модули:

import { promises as fs } from 'fs';

После этого все методы, которые вы будете использовать (readFile, writeFile, unlink, и др.), возвращают промис.

2. Основные методы fs.promises и их применение

Чтение файла: fs.readFile

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

async function readTextFile() {
    try {
        const data = await fs.readFile('data.txt', 'utf-8');
        console.log('Содержимое файла:', data);
    } catch (err) {
        console.error('Ошибка чтения файла:', err);
    }
}

readTextFile();
  • Первый аргумент — путь к файлу.
  • Второй аргумент — кодировка (например, 'utf-8'). Если не указать, получите буфер (не строку!).

Запись файла: fs.writeFile

async function writeTextFile() {
    try {
        await fs.writeFile('data.txt', 'Привет, Node.js!');
        console.log('Файл успешно записан!');
    } catch (err) {
        console.error('Ошибка записи файла:', err);
    }
}

writeTextFile();
  • Если файла не существует — будет создан.
  • Если существует — будет перезаписан (осторожно!).

Добавление в файл: fs.appendFile

async function appendTextFile() {
    try {
        await fs.appendFile('data.txt', '\nДобавленная строка!');
        console.log('Данные успешно добавлены!');
    } catch (err) {
        console.error('Ошибка добавления данных:', err);
    }
}

appendTextFile();

Удаление файла: fs.unlink

async function deleteFile() {
    try {
        await fs.unlink('data.txt');
        console.log('Файл удалён!');
    } catch (err) {
        console.error('Ошибка удаления файла:', err);
    }
}

deleteFile();

Проверка существования файла

Внимание: в fs.promises нет метода exists(). Вместо этого используйте обработку ошибок:

async function checkFileExists(path) {
    try {
        await fs.access(path);
        console.log('Файл существует!');
    } catch {
        console.log('Файл не найден!');
    }
}

checkFileExists('data.txt');

fs.access() выбрасывает ошибку, если файла нет.

4. Практика: мини-приложение "Заметки"

Давайте продолжим развивать наше мини-приложение — простую систему заметок, которую мы начинали в предыдущих лекциях.

Задача: список заметок хранится в файле notes.json. Нужно реализовать функции:

  • Добавить новую заметку
  • Прочитать все заметки
  • Удалить заметку по индексу

1. Чтение всех заметок

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

async function getNotes() {
    try {
        const data = await fs.readFile('notes.json', 'utf-8');
        return JSON.parse(data);
    } catch (err) {
        // Если файла нет — возвращаем пустой массив
        if (err.code === 'ENOENT') {
            return [];
        }
        throw err;
    }
}

(async () => {
    const notes = await getNotes();
    console.log('Все заметки:', notes);
})();

2. Добавление новой заметки

async function addNote(text) {
    const notes = await getNotes();
    notes.push({ text, created: new Date().toISOString() });
    await fs.writeFile('notes.json', JSON.stringify(notes, null, 2));
    console.log('Заметка добавлена!');
}

addNote('Купить хлеб');

3. Удаление заметки по индексу

async function removeNote(index) {
    const notes = await getNotes();
    if (index < 0 || index >= notes.length) {
        console.log('Нет заметки с таким индексом');
        return;
    }
    notes.splice(index, 1);
    await fs.writeFile('notes.json', JSON.stringify(notes, null, 2));
    console.log('Заметка удалена!');
}

removeNote(0);

4. Асинхронность и параллелизм

Важно помнить: если вы одновременно запускаете несколько операций записи в один и тот же файл, возможны гонки данных. Лучше избегать параллельных записей или использовать блокировки (но это тема для продвинутых курсов).

5. Типичные ошибки при работе с fs.promises и async/await

Ошибка №1: забыли добавить await перед асинхронным вызовом.
Если забыть await, функция вернёт промис, а не результат. В итоге, вместо данных вы получите [object Promise] или вообще ничего не произойдёт.

const data = fs.readFile('file.txt', 'utf-8'); // ошибка: data — это промис!
console.log(data); // Promise { <pending> }

Ошибка №2: используете await вне async-функции.
В CommonJS-модулях так делать нельзя, получите ошибку: "SyntaxError: await is only valid in async functions".

Ошибка №3: не обрабатываете ошибки.
Если не обернуть асинхронный код в try/catch, ошибки могут остаться незамеченными и привести к падению программы.

Ошибка №4: забыли указать кодировку при чтении текстовых файлов.
Если не указать 'utf-8', получите буфер, а не строку.

const data = await fs.readFile('file.txt'); // data — это Buffer!

Ошибка №5: параллельные записи в один и тот же файл.
Если одновременно запустить несколько функций, которые пишут в один и тот же файл, возможна потеря данных.

1
Задача
Модуль 4: Node.js, Next.js и Angular, 3 уровень, 5 лекция
Недоступна
Чтение содержимого текстового файла с помощью fs.promises
Чтение содержимого текстового файла с помощью fs.promises
1
Задача
Модуль 4: Node.js, Next.js и Angular, 3 уровень, 5 лекция
Недоступна
Запись новой строки в файл с помощью fs.promises и async/await
Запись новой строки в файл с помощью fs.promises и async/await
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ