Node.js створює папку або використовує існуючі


186

Я вже прочитав документацію на Node.js і, якщо я щось пропустив, він не вказує, які параметри містяться в певних операціях, зокрема fs.mkdir(). Як ви бачите в документації, це не дуже багато.

На даний момент у мене є цей код, який намагається створити папку або використовувати замість цього наявну:

fs.mkdir(path,function(e){
    if(!e || (e && e.code === 'EEXIST')){
        //do something with contents
    } else {
        //debug
        console.log(e);
    }
});

Але мені цікаво, чи це правильний спосіб зробити це? Чи перевірка коду EEXISTє правильним способом знати, що папка вже існує? Я знаю, що можу зробити fs.stat()до створення каталогу, але це вже два звернення до файлової системи.

По-друге, чи є повна або хоча б більш детальна документація Node.js, яка містить детальну інформацію про те, що містять об'єкти помилок, які параметри означають і т.д.


31
Маленький нитчик, але позбудься цього e &&. Якщо !eне вдається, то ви знаєте, що eце правда.
Я ненавиджу ледачий

Відповіді:


236

Хороший спосіб зробити це - використовувати модуль mkdirp .

$ npm install mkdirp

Використовуйте його для запуску функції, яка потребує каталогу. Зворотний виклик викликається після створення шляху або якщо шлях вже існує. Помилка errвстановлюється, якщо mkdirp не вдалося створити шлях до каталогу.

var mkdirp = require('mkdirp');
mkdirp('/tmp/some/path/foo', function(err) { 

    // path exists unless there was an error

});

3
Мені здається, правильним (читати "не залежно додано") відповідь буде відповідь на низький рівень, використовуючи @Raugaral fs.exists(Sync).
Рікардо Педроні

@meawoppl, це 'makedirectory'p. 'P' невідомо.
andrew

4
@RicardoPedroni Правильним способом є використання модуля. Модулі, як правило, відверто намагаються вирішити одну проблему і часто підтримуються. Ви можете легко їх оновити за допомогою npm. Крім того, вам слід уникати використання fs.exists [Sync], оскільки його використання передбачає перегони.
1j01

16
@ 1j01 Я не вірю, що правильним способом є використання модуля, якщо платформа споконвічно підтримує операцію. Це дорога до хаосу. Я повинен погодитися, що з технічної точки зору є кращі відповіді.
c ..

2
@ 1j01 Також використання операцій синхронізації означає умови перегонів, оскільки їх використання для них є роздільною здатністю.
c ..

193

Редагувати: Оскільки ця відповідь дуже популярна, я оновив її, щоб відображати сучасну практику.

Вузол> = 10

Нова { recursive: true }опція Node fsтепер дозволяє це спочатку. Цей параметр імітує поведінку UNIXmkdir -p . Він буде рекурсивно переконуватись, що існує кожна частина шляху, і не призведе до помилки, якщо хтось із них.

(Примітка. Це може все-таки видавати помилки, такі як EPERMабо EACCESS, тому краще все-таки загорнути його вtry {} catch (e) {} якщо ваша реалізація сприйнятлива.)

Синхронна версія.

fs.mkdirSync(dirpath, { recursive: true })

Асинхронна версія

await fs.promises.mkdir(dirpath, { recursive: true })

Старіші версії вузла

Використання a try {} catch (err) {} , ви можете досягти цього дуже витончено, не стикаючись з умовами перегонів.

Щоб запобігти мертвому часу між перевіркою на існування та створенням каталогу, ми просто намагаємось створити його прямо вгору та ігнорувати помилку, якщо вона є EEXIST (каталог вже існує).

Якщо ж помилки немає EEXIST, нам слід викинути помилку, оскільки ми могли мати справу з чимось на зразок EPERMабоEACCES

function ensureDirSync (dirpath) {
  try {
    return fs.mkdirSync(dirpath)
  } catch (err) {
    if (err.code !== 'EEXIST') throw err
  }
}

Для mkdir -p-like рекурсивного поведінки, наприклад ./a/b/c, ви повинні були б назвати його на кожній частині dirpath, наприклад ./a, ./a/b,.a/b/c


var fs = Npm.require ('fs'); var dir = process.env.PWD + '/ файли / користувачі /' + this.userId + '/'; спробуйте {fs.mkdirSync (dir); } catch (e) {if (e.code! = 'EEXIST') кинути e; }
Аарон

Я спробував ваш код, створив js-скрипт, який використовує створення каталогу так: mkdirpSync (path.join (__ dirname, 'first', 'second', 'third', 'ololol', 'works')); Але отримала цю помилку: $ node 1.js fs.js: 747 returninding.mkdir (pathModule._makeLong (path), ^ Помилка: EPERM, операція не дозволена 'C: \' у Error (native) на Object.fs. mkdirSync (fs.js: 747: 18) у mkdirpSync (C: \ Users \ MAXIM \ Desktop \ test \ 1.js: 15: 8) на Object. <anonymous> (C: \ Users \ MAXIM \ Desktop \ test \ 1.js: 19: 1) ... Чи можете ви підказати, що може бути не так? Використовується у Windows, очевидно :)
Alendorff

EPERM, схоже, видає дозвіл, тому сценарій все-таки був би порушеним виконанням
Крістоф Маруа

Я думаю, що було б краще: var mkdirpSync = функція (dirpath) {var parts = dirpath.split (path.sep); for (var i = 1; i <= parts.length; i ++) {спробуйте {fs.mkdirSync (path.join.apply (null, parts.slice (0, i))); } catch (помилка) {if (error.code! = 'EEXIST') {помилка кидка; }}}}
маніш

1
попередження: він не працює, якщо ваш шлях починається з /
acemtp

62

Якщо ви хочете швидко забруднити один вкладиш, скористайтеся цим:

fs.existsSync("directory") || fs.mkdirSync("directory");


7
fs.existsSync (...) не застаріло, тому ця відповідь здається нормальною.
Ден Хейвуд

Голова вгору! Не працюватиме для "dir / foo / bar", тобто не вистачає функції прапора mkdir -p
Карл Покус

У цьому також є перегони
Еверт

26

Документи node.js для в fs.mkdirосновному відкладаються на сторінку man для Linux mkdir(2). Це вказує на цеEEXIST також буде вказано, якщо шлях існує, але це не каталог, який створює незручний кутовий випадок, якщо ви йдете цим маршрутом.

Можливо, вам буде краще зателефонувати, fs.statякий підкаже, чи існує шлях і чи це каталог в одному виклику. Оскільки (я припускаю, що це) звичайний випадок, коли каталог вже існує, це лише одна файлова система.

Ці fsмодульні методи - це тонкі обгортки навколо рідних API API, тому вам доведеться перевірити детальні сторінки, на які посилаються в документах node.js, на деталі.


19
Якщо дзвонити statраніше mkdir, це може призвести до перегонів - врахуйте це.
Роджер Ліпскомб

24

Ви можете скористатися цим:

if(!fs.existsSync("directory")){
    fs.mkdirSync("directory", 0766, function(err){
        if(err){
            console.log(err);
            // echo the result back
            response.send("ERROR! Can't make the directory! \n");
        }
    });
}

1
-1. Я не вірю, що це працює, statSyncпризведе до помилки, якщо сутність взагалі не існує, збій коду. Це потрібно загортати в try/catchблок.
Кріс Фостер

2
Вибачте, я помиляюся змінити "statSync" на "існуєSync"
Raugaral

5
Відповідно до nodejs.org/api/fs.html#fs_fs_mkdirsync_path_mode варіант синхронізації mkdir не приймає зворотний дзвінок
danwellman

1
Відповідно до nodejs.org/api/fs.html#fs_fs_existssync_path , fs.existsSync()і fs.exists()буде застарілим.
pau.moreno

7

Я пропоную рішення без модулів (накопичувальні модулі ніколи не рекомендуються для ремонту, особливо для невеликих функцій, які можна записати в декілька рядків ...):

ОСТАННЄ ОНОВЛЕННЯ :

У версії 10.10.0 NodeJS рекурсивні параметри:

// Create recursive folder
fs.mkdir('my/new/folder/create', { recursive: true }, (err) => { if (err) throw err; });

ОНОВЛЕННЯ:

// Get modules node
const fs   = require('fs');
const path = require('path');

// Create 
function mkdirpath(dirPath)
{
    if(!fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK))
    {
        try
        {
            fs.mkdirSync(dirPath);
        }
        catch(e)
        {
            mkdirpath(path.dirname(dirPath));
            mkdirpath(dirPath);
        }
    }
}

// Create folder path
mkdirpath('my/new/folder/create');

fs.exists()застаріло у вузлі v9. використовувати fs.access()замість цього. (повертається, undefinedякщо файл існує; інакше видає помилку ENOENT)
chharvey

Без будь-якого пакету npm працює. Це цінний код. Спасибі
Картік Шрідхаран

Цей досить кращий для створення папки під існуючим довгим шляхом;) Спасибі, чоловіче.
Tsung Goh

1
Про що fs.mkdirSync('my/new/folder/create', {recursive: true})?
Сайто

Дякую ! Я оновлюю свою посаду, щоб допомогти іншим. Вузол 10.12.0 був надто недавним.
Liberateur

4

Ви також можете використовувати fs-extra , які забезпечують багато часто використовуваних файлових операцій.

Приклад коду:

var fs = require('fs-extra')

fs.mkdirs('/tmp/some/long/path/that/prob/doesnt/exist', function (err) {
  if (err) return console.error(err)
  console.log("success!")
})

fs.mkdirsSync('/tmp/another/path')

документи тут: https://github.com/jprichardson/node-fs-extra#mkdirsdir-callback


4

Ось код ES6, який я використовую для створення каталогу (коли його не існує):

const fs = require('fs');
const path = require('path');

function createDirectory(directoryPath) {
  const directory = path.normalize(directoryPath);

  return new Promise((resolve, reject) => {
    fs.stat(directory, (error) => {
      if (error) {
        if (error.code === 'ENOENT') {
          fs.mkdir(directory, (error) => {
            if (error) {
              reject(error);
            } else {
              resolve(directory);
            }
          });
        } else {
          reject(error);
        }
      } else {
        resolve(directory);
      }
    });
  });
}

const directoryPath = `${__dirname}/test`;

createDirectory(directoryPath).then((path) => {
  console.log(`Successfully created directory: '${path}'`);
}).catch((error) => {
  console.log(`Problem creating directory: ${error.message}`)
});

Примітка:

  • На початку createDirectory функції я нормалізую шлях, щоб гарантувати, що тип сепаратора шляху операційної системи буде використовуватися послідовно (наприклад, це перетвориться C:\directory/testна C:\directory\test(при знаходженні в Windows)
  • fs.exists є застарілим , тому я використовуюfs.stat , щоб перевірити , якщо каталог вже існує
  • Якщо каталог не існує, код помилки буде ENOENT( E rror NO ENT ry)
  • Сам каталог буде створений за допомогою fs.mkdir
  • Я віддаю перевагу асинхронній функції fs.mkdirнад тим, що блокує аналог, fs.mkdirSyncі завдяки обгортанню Promiseбуде гарантовано, що шлях до каталогу буде повернутий лише після успішного створення каталогу

Дякуємо за чисте рішення, яке не передбачає зайвих модулів. Це прекрасно працювало для мене. Мені б хотілося, щоб відповідей було більше!
Кен Ліон

3

На мою думку, краще не рахувати звернень файлової системи, кодуючи в Javascript. Тим НЕ менше, (1) statі mkdir(2) mkdirі чек (або відкидання) код помилки, обидва шляхи правильні способи зробити те , що ви хочете.


-1, я не бачу, як перевірка чи відмова можуть бути правильними способами зробити це. Це майже не відповідає.
Метт Бал

Це хороший спосіб mkdir каталогу або використання наявного. Я не бачу, чому ти не бачиш. Перевірка коду помилки ввічливо хороша, а відкидання коду помилки - лише хороший. ви не згодні?
Чул-Вунг Ян

1
Можливо, це проблема мовного бар'єру, але я читаю це як просто не відповівши на питання, яке задає ОП.
Метт Баль

Я бачу, у чому тобі справа. Однак я вважаю, що існує багато способів зробити все правильно. Дякую.
Чул-Вунг Ян

2

створити динамічний каталог імен для кожного користувача ... використовувати цей код

***suppose email contain user mail address***

var filessystem = require('fs');
var dir = './public/uploads/'+email;

if (!filessystem.existsSync(dir)){
  filessystem.mkdirSync(dir);

}else
{
    console.log("Directory already exist");
}

1

Все це можна зробити за допомогою модуля Файлова система.

const
  fs = require('fs'),
  dirPath = `path/to/dir`

// Check if directory exists.
fs.access(dirPath, fs.constants.F_OK, (err)=>{
  if (err){
    // Create directory if directory does not exist.
    fs.mkdir(dirPath, {recursive:true}, (err)=>{
      if (err) console.log(`Error creating directory: ${err}`)
      else console.log('Directory created successfully.')
    })
  }
  // Directory now exists.
})

Вам навіть не потрібно перевіряти, чи існує каталог. Наступний код також гарантує, що каталог або вже існує, або створений.

const
  fs = require('fs'),
  dirPath = `path/to/dir`

// Create directory if directory does not exist.
fs.mkdir(dirPath, {recursive:true}, (err)=>{
  if (err) console.log(`Error creating directory: ${err}`)
  // Directory now exists.
})

0

Відповідь Раугарала, але з функцією -p. Некрасиво, але це працює:

function mkdirp(dir) {
    let dirs = dir.split(/\\/).filter(asdf => !asdf.match(/^\s*$/))
    let fullpath = ''

    // Production directory will begin \\, test is on my local drive.
    if (dirs[0].match(/C:/i)) {
        fullpath = dirs[0] + '\\'
    }
    else {
        fullpath = '\\\\' + dirs[0] + '\\'
    }

    // Start from root directory + 1, build out one level at a time.
    dirs.slice(1).map(asdf => {
        fullpath += asdf + '\\'
        if (!fs.existsSync(fullpath)) {
            fs.mkdirSync(fullpath)
        }
    })
}//mkdirp

0

Як новіша альтернатива відповіді Теему Іконен , яка дуже проста і легко читається, - це використовувати ensureDirметод fs-extraпакету.

Він не тільки може бути використаний як кричуща заміна вбудованого fsмодуля, але також має безліч інших функцій, крім функціональних можливостей fsпакета.

ensureDirМетод, як випливає з назви, гарантує , що каталог існує. Якщо структури каталогів не існує, вона створюється. Як mkdir -p. Не лише кінцева папка, натомість створюється весь шлях, якщо він уже не існує.

наведений вище - його asyncверсія. Він також має синхронний метод для виконання цього у вигляді ensureDirSyncметоду.


0

@ Відповідь Лібератера вище для мене не працювала (Node v8.10.0). Невелика модифікація зробила трюк, але я не впевнений, чи це правильний шлях. Будь ласка, підкажіть.

// Get modules node
const fs   = require('fs');
const path = require('path');

// Create
function mkdirpath(dirPath)
{
    try {
        fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK);
    }
    catch(err) {
        try
        {
            fs.mkdirSync(dirPath);
        }
        catch(e)
        {
            mkdirpath(path.dirname(dirPath));
            mkdirpath(dirPath);
        }
    }
}

// Create folder path
mkdirpath('my/new/folder/create');
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.