Пошук уроків, статей та іншого контенту
Порівняйте синхронні й асинхронні операції та використайте проміси й async/await для роботи з файлами.
Node.js має вбудований модуль fs для роботи з файловою системою:
читання файлів;
запис і дописування даних;
перейменування та видалення;
створення каталогів;
перевірка наявності файлів.
Операції з файловою системою можуть бути:
синхронними — блокують виконання JavaScript, доки операція не завершиться;
асинхронними — запускають операцію та дозволяють виконувати інший код, поки система працює з файлом.
Для серверних програм зазвичай використовують асинхронні операції.
Синхронні методи мають суфікс Sync. Наприклад:
const fs = require('node:fs');
console.log('Початок');
const text = fs.readFileSync('message.txt', 'utf8');
console.log(text);
console.log('Кінець');Спочатку Node.js прочитає весь файл, і лише після цього виконає наступний console.log.
Якщо файл великий або операція виконується повільно, синхронний виклик блокує потік виконання. У серверному застосунку це означає, що Node.js тимчасово не зможе обробляти інші запити.
Синхронні методи можуть бути зручними для:
невеликих одноразових скриптів;
початкового завантаження конфігурації;
простих навчальних прикладів.
Для обробки запитів вебсервера краще використовувати асинхронні методи.
Асинхронний API можна імпортувати з модуля node:fs/promises:
const fs = require('node:fs/promises');Методи цього модуля повертають проміси. Проміс представляє результат операції, яка завершиться зараз або пізніше.
Наприклад, асинхронне читання файлу:
const fs = require('node:fs/promises');
console.log('Початок');
fs.readFile('message.txt', 'utf8')
.then((text) => {
console.log(text);
})
.catch((error) => {
console.error('Не вдалося прочитати файл:', error.message);
});
console.log('Кінець');Результат console.log('Кінець') може з’явитися раніше за вміст файлу. Node.js запускає читання, але не зупиняє виконання всього іншого коду.
Модуль node:fs/promises містить методи, які відповідають звичним операціям із файлами:
readFile() — прочитати файл;
writeFile() — записати дані у файл;
appendFile() — додати дані в кінець файлу;
mkdir() — створити каталог;
rename() — перейменувати або перемістити файл;
unlink() — видалити файл;
stat() — отримати інформацію про файл.
Більшість методів приймають шлях до файлу та, за потреби, параметри операції.
const fs = require('node:fs/promises');
fs.readFile('message.txt', 'utf8')
.then((text) => {
console.log(text);
})
.catch((error) => {
console.error(error);
});Параметр 'utf8' перетворює вміст файлу на рядок. Без цього параметра результатом буде об’єкт Buffer, який містить байти файлу.
const fs = require('node:fs/promises');
fs.writeFile('message.txt', 'Привіт, Node.js!', 'utf8')
.then(() => {
console.log('Файл записано');
})
.catch((error) => {
console.error('Помилка запису:', error.message);
});Якщо файл уже існує, writeFile() замінює його вміст. Якщо файлу немає, Node.js створює його.
Щоб не замінювати наявний вміст, використовуйте appendFile():
const fs = require('node:fs/promises');
fs.appendFile('log.txt', 'Новий запис\n', 'utf8')
.then(() => {
console.log('Запис додано');
})
.catch((error) => {
console.error('Помилка:', error.message);
});async/awaitЛанцюжок .then() і .catch() працює, але послідовність кількох операцій може стати важкою для читання. Для цього часто використовують async/await.
await призупиняє виконання поточної асинхронної функції, доки проміс не завершиться. Інші операції Node.js при цьому можуть продовжувати виконуватися.
const fs = require('node:fs/promises');
async function readMessage() {
const text = await fs.readFile('message.txt', 'utf8');
console.log(text);
}
readMessage();await можна використовувати всередині функції, оголошеної з async.
try...catchАсинхронна операція може завершитися помилкою:
файл не існує;
немає дозволу на читання;
вказано неправильний шлях;
каталог для нового файлу відсутній.
У разі використання async/await помилки обробляють через try...catch:
const fs = require('node:fs/promises');
async function readMessage() {
try {
const text = await fs.readFile('message.txt', 'utf8');
console.log('Вміст файлу:');
console.log(text);
} catch (error) {
console.error('Не вдалося прочитати файл:', error.message);
}
}
readMessage();Якщо readFile() завершиться помилкою, виконання перейде до блоку catch.
Коли наступна операція залежить від результату попередньої, використовуйте кілька await послідовно.
const fs = require('node:fs/promises');
async function updateFile() {
try {
await fs.writeFile(
'profile.txt',
'Ім’я: Олена\nРоль: розробниця',
'utf8'
);
const profile = await fs.readFile('profile.txt', 'utf8');
console.log(profile);
} catch (error) {
console.error('Помилка роботи з файлом:', error.message);
}
}
updateFile();У цьому прикладі читання починається після завершення запису. Це важливо, тому що файл має вже містити нові дані.
Наступна програма:
створює текстовий файл;
читає його;
додає новий рядок;
читає оновлений вміст;
обробляє можливі помилки.
const fs = require('node:fs/promises');
async function main() {
const fileName = 'notes.txt';
try {
await fs.writeFile(
fileName,
'Перша нотатка\n',
'utf8'
);
const firstRead = await fs.readFile(fileName, 'utf8');
console.log('Початковий вміст:');
console.log(firstRead);
await fs.appendFile(
fileName,
'Друга нотатка\n',
'utf8'
);
const secondRead = await fs.readFile(fileName, 'utf8');
console.log('Оновлений вміст:');
console.log(secondRead);
} catch (error) {
console.error('Операцію не виконано:', error.message);
}
}
main();Збережіть код у файлі file-demo.js і запустіть:
node file-demo.jsПісля запуску в поточному каталозі з’явиться файл notes.txt.
Синхронний варіант:
const fs = require('node:fs');
const text = fs.readFileSync('message.txt', 'utf8');
console.log(text);Асинхронний варіант із async/await:
const fs = require('node:fs/promises');
async function readFile() {
const text = await fs.readFile('message.txt', 'utf8');
console.log(text);
}
readFile();Основна різниця:
синхронний метод блокує виконання до завершення операції;
асинхронний метод повертає проміс;
async/await дає змогу записати асинхронний код у зрозумілому послідовному стилі;
асинхронна операція не обов’язково завершується швидше, але вона не блокує основний потік Node.js.
await поза асинхронною функцієюНеправильно:
const fs = require('node:fs/promises');
const text = await fs.readFile('message.txt', 'utf8');У звичайному CommonJS-файлі await потрібно використовувати всередині async-функції:
const fs = require('node:fs/promises');
async function readFile() {
const text = await fs.readFile('message.txt', 'utf8');
console.log(text);
}
readFile();Якщо файл може бути відсутнім або недоступним, використовуйте try...catch:
async function readFile() {
try {
// Читаємо файл і обробляємо можливу помилку
const text = await fs.readFile('unknown.txt', 'utf8');
console.log(text);
} catch (error) {
console.error(error.message);
}
}Без 'utf8' результатом буде Buffer:
const data = await fs.readFile('message.txt');
console.log(data);Для отримання рядка вкажіть кодування:
const text = await fs.readFile('message.txt', 'utf8');
console.log(text);writeFile() замість appendFile()writeFile() замінює весь вміст файлу:
await fs.writeFile('log.txt', 'Новий запис\n', 'utf8');Для додавання даних використовуйте:
await fs.appendFile('log.txt', 'Ще один запис\n', 'utf8');Відносний шлях зазвичай обчислюється від поточного робочого каталогу, з якого запущено команду node.
Наприклад:
await fs.readFile('data/message.txt', 'utf8');Цей шлях означає, що каталог data має бути доступним від поточного каталогу запуску програми.
Для роботи з файлами в Node.js використовується вбудований модуль fs.
Методи з суфіксом Sync є синхронними та блокують виконання.
Методи з node:fs/promises працюють асинхронно та повертають проміси.
async/await дає змогу зручно працювати з асинхронними операціями.
Помилки асинхронних операцій обробляють через try...catch.
readFile() читає файл, writeFile() записує або замінює вміст, а appendFile() додає дані в кінець.
Для серверних застосунків переважно використовують асинхронний File System API.