Як працює модуль File System (fs) у Node.js?
Модуль fs у Node.js
Модуль fs (File System) є основним модулем Node.js, який надає API для взаємодії з файловою системою. Він дозволяє читати, записувати, оновлювати, видаляти та спостерігати за файлами і каталогами.
Три стилі API
Node.js fs надає три стилі для кожної операції:
1. На основі зворотного виклику (оригінальний)
js
const fs = require('fs');
fs.readFile('data.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});2. Синхронний (блокуючий)
js
const fs = require('fs');
const data = fs.readFileSync('data.txt', 'utf8');
console.log(data);3. На основі обіцянок (рекомендується)
js
const fs = require('fs/promises');
async function readData() {
const data = await fs.readFile('data.txt', 'utf8');
console.log(data);
}Загальні операції
Читання файлів
js
const fs = require('fs/promises');
// Читання як рядок
const text = await fs.readFile('file.txt', 'utf8');
// Читання як Buffer (бінарний)
const buffer = await fs.readFile('image.png');Запис файлів
js
// Запис (створює або перезаписує)
await fs.writeFile('output.txt', 'Hello World');
// Додавання до файлу
await fs.appendFile('log.txt', 'New log entry\n');Робота з каталогами
js
// Створення каталогу
await fs.mkdir('new-folder', { recursive: true });
// Читання вмісту каталогу
const files = await fs.readdir('src');
// Читання з типами файлів
const entries = await fs.readdir('src', { withFileTypes: true });
entries.forEach(entry => {
console.log(`${entry.name} - ${entry.isDirectory() ? 'каталог' : 'файл'}`);
});Інформація про файл
js
const stats = await fs.stat('file.txt');
console.log({
size: stats.size, // байти
isFile: stats.isFile(),
isDir: stats.isDirectory(),
created: stats.birthtime,
modified: stats.mtime
});Видалення та перейменування
js
// Видалення файлу
await fs.unlink('old-file.txt');
// Видалення каталогу (рекурсивно)
await fs.rm('old-folder', { recursive: true, force: true });
// Перейменування / переміщення
await fs.rename('old-name.txt', 'new-name.txt');
// Копіювання файлу
await fs.copyFile('source.txt', 'dest.txt');Потокове оброблення великих файлів
Для великих файлів використовуйте потоки замість readFile, щоб уникнути завантаження всього файлу в пам'ять:
js
const fs = require('fs');
const readStream = fs.createReadStream('large-file.csv', 'utf8');
const writeStream = fs.createWriteStream('output.csv');
readStream.pipe(writeStream);
readStream.on('end', () => console.log('Готово!'));
readStream.on('error', (err) => console.error(err));Спостереження за файлами
js
const fs = require('fs');
// Спостереження за змінами файлу
const watcher = fs.watch('config.json', (eventType, filename) => {
console.log(`${filename} змінено: ${eventType}`);
});
// Або використовуйте fs.watchFile для спостереження на основі опитування
fs.watchFile('data.txt', { interval: 1000 }, (curr, prev) => {
console.log(`Файл змінено о: ${curr.mtime}`);
});Важливі міркування
| Тема | Найкраща практика |
|---|---|
| Кодування | Завжди вказуйте 'utf8' для текстових файлів |
| Обробка помилок | Завжди обробляйте помилки (try/catch або зворотний виклик) |
| Великі файли | Використовуйте потоки, а не readFile |
| Синхронні методи | Уникайте в коді сервера (блокує цикл подій) |
| Шляхи | Використовуйте path.join() для крос-платформених шляхів |
| Безпека | Перевіряйте шляхи, надані користувачем, щоб запобігти обходу каталогів |
js
const path = require('path');
// ✅ Безпечне створення шляху
const safePath = path.join(__dirname, 'uploads', path.basename(userInput));
// ❌ Вразливий до обходу каталогів
const unsafePath = './uploads/' + userInput;
// userInput = '../../etc/passwd'Порада: Завжди віддавайте перевагу
fs/promisesдля сучасного асинхронного коду. Використовуйте потоки для файлів більше ~50MB. Ніколи не використовуйте синхронні методи в обробниках запитів сервера.
Коротка відповідь
Для співбесідиPremium
Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.