Как создать директорию, если она не существует, с помощью Node.js
Правильный ли следующий способ создания директории, если она не существует? Директория должна иметь полные права для скрипта и быть доступной для чтения другими.
var dir = __dirname + '/upload';
if (!path.existsSync(dir)) {
fs.mkdirSync(dir, 0744);
}
Предоставленный вами код является разумным подходом, но имеет некоторые потенциальные проблемы, которые следует решить для более надежного создания каталогов в Node.js. Хотя он будет работать во многих случаях, существуют лучшие практики, особенно в отношении разрешений и обработки ошибок.
Содержание
- Базовые методы создания каталогов
- Понимание режимов разрешений
- Обработка ошибок и условия гонки
- Рекурсивное создание каталогов
- Рекомендуемые подходы
- Лучшие практики для разрешений
- Современные решения для Node.js
Базовые методы создания каталогов
В Node.js существует несколько вариантов создания каталогов:
Синхронный подход (Ваш текущий метод)
const fs = require('fs');
const path = require('path');
var dir = path.join(__dirname, 'upload');
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, 0744);
}
Асинхронный подход (Рекомендуется)
const fs = require('fs');
const path = require('path');
const dir = path.join(__dirname, 'upload');
fs.mkdir(dir, { recursive: true }, (err) => {
if (err) {
console.error('Ошибка создания каталога:', err);
} else {
console.log('Каталог успешно создан');
}
});
Понимание режимов разрешений
Ваш код использует 0744 в качестве режима разрешений, но есть важные нюансы:
- Восьмеричная нотация: Node.js ожидает режимы разрешений в восьмеричном формате (с префиксом
0), поэтому0744является правильным - Фактические разрешения: Режим
0744предоставляет:- Владельцу: чтение, запись, выполнение (7)
- Группе: только чтение (4)
- Остальным: только чтение (4)
Однако исследования показывают, что параметр mode в fs.mkdir() ведет себя непоследовательно в разных версиях Node.js. Согласно проблемам на GitHub Node.js, фактические создаваемые разрешения могут не соответствовать тому, что вы указали в параметре mode.
Обработка ошибок и условия гонки
Ваш текущий подход имеет потенциальное условие гонки:
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, 0744);
}
Между проверкой existsSync и вызовом mkdirSync другой процесс может создать каталог, что приведет к ошибке. Более надежные решения обрабатывают эту ошибку:
try {
fs.mkdirSync(dir, 0744);
} catch (err) {
if (err.code !== 'EEXIST') {
throw err; // Повторно выбрасываем, если это не ошибка "каталог уже существует"
}
}
Рекурсивное создание каталогов
Для создания вложенных каталогов (например, path/to/nested/folder) требуется опция recursive: true:
// Создание вложенных каталогов
const nestedDir = path.join(__dirname, 'data', 'files', 'uploads');
fs.mkdirSync(nestedDir, { recursive: true, mode: 0o755 });
Без recursive: true будет создан только последний каталог в пути, и операция завершится ошибкой, если родительские каталоги не существуют.
Рекомендуемые подходы
1. Простой синхронный метод (с обработкой ошибок)
const fs = require('fs');
const path = require('path');
function ensureDirectoryExists(dirPath, mode = 0o755) {
try {
fs.mkdirSync(dirPath, { recursive: true, mode });
return true;
} catch (err) {
if (err.code === 'EEXIST') {
return false; // Каталог уже существует
}
throw err; // Повторно выбрасываем другие ошибки
}
}
const dir = path.join(__dirname, 'upload');
ensureDirectoryExists(dir, 0o744);
2. Современный подход с async/await
const fs = require('fs').promises;
const path = require('path');
async function ensureDirectoryExists(dirPath, mode = 0o755) {
try {
await fs.mkdir(dirPath, { recursive: true, mode });
return true;
} catch (err) {
if (err.code === 'EEXIST') {
return false; // Каталог уже существует
}
throw err; // Повторно выбрасываем другие ошибки
}
}
// Использование
(async () => {
const dir = path.join(__dirname, 'upload');
await ensureDirectoryExists(dir, 0o744);
})();
Лучшие практики для разрешений
Для полного разрешения для скрипта и доступности для чтения другими:
- Используйте
0o775для сценариев групповой работы - Используйте
0o755для стандартных каталогов веб-сервера - Осторожно используйте
0o777(полный доступ для всех)
Обратите внимание, что фактические разрешения также могут быть affected:
- Настройкой umask системы
- Ограничениями файловой системы
- Разрешениями родительского каталога
Современные решения для Node.js
Для Node.js v10.12.0 и выше рекомендуется нативный fs.mkdir() с { recursive: true } вместо внешних библиотек вроде mkdirp, если вам не нужно поддерживать старые версии Node.js.
Оценка вашего кода:
var dir = __dirname + '/upload';
if (!path.existsSync(dir)) {
fs.mkdirSync(dir, 0744);
}
Плюсы:
- Простой и читаемый
- Использует проверку существования для избежания ошибок
- Использует правильную восьмеричную нотацию для разрешений
Минусы:
- Условие гонки между проверкой и созданием
- Нет обработки других потенциальных ошибок
- Использует устаревший
path.existsSync()(рассмотрите использованиеfs.existsSync()) - Не обрабатывает рекурсивное создание каталогов
- Поведение режима разрешений может быть непоследовательным
Улучшенная версия:
const fs = require('fs');
const path = require('path');
function safeCreateDirectory(dir, mode = 0o744) {
try {
fs.mkdirSync(dir, { recursive: true, mode });
} catch (err) {
if (err.code !== 'EEXIST') {
throw err;
}
}
}
const dir = path.join(__dirname, 'upload');
safeCreateDirectory(dir, 0o744);
Этот подход обеспечивает большую надежность и следует лучшим практикам Node.js.
Источники
- How to create a directory if it doesn’t exist using Node.js - Stack Overflow
- Creating Directories in Node.js: A Guide to fs.mkdir() - Medium
- Node.js fs.mkdirSync() Method - GeeksforGeeks
- Using fs.mkdir() make a directory according the Docs the argument ‘mode’ defaults to 0o777, but actually it’s not - GitHub Issue
- mkdirp - npm
- Node.js — Working with folders in Node.js - Official Documentation
Заключение
- Ваш текущий подход будет работать, но имеет проблемы с надежностью
- Всегда обрабатывайте ошибки при создании каталогов
- Используйте
{ recursive: true }для создания вложенных каталогов - Рассмотрите использование паттернов async/await для лучшей производительности
- Помните, что поведение режима разрешений может варьироваться в разных версиях Node.js
- Для полных разрешений скрипта и доступа для чтения другими,
0o755или0o775обычно более подходят, чем0o744
Предоставленные выше улучшенные решения обеспечивают лучшую обработку ошибок, поддержку рекурсивного создания каталогов и следуют современным лучшим практикам Node.js.