web-dev-qa-db-fra.com

noeud comment créer un répertoire s'il n'existe pas?

Est-ce la bonne façon de créer un répertoire s'il n'existe pas? Il devrait avoir une permission complète pour le script et lisible par d'autres.

var dir = __dirname + '/upload';
if (!path.existsSync(dir)) {
    fs.mkdirSync(dir, 0744);
}
499
Whisher
var fs = require('fs');
var dir = './tmp';

if (!fs.existsSync(dir)){
    fs.mkdirSync(dir);
}
970
chovy

Non, pour plusieurs raisons.

  1. Le module path n'a pas de méthode exists/existsSync. C'est dans le fs module. (Peut-être que vous venez de faire une faute de frappe dans votre question?)

  2. Les documents vous déconseillent explicitement ​​d'utiliser exists.

    fs.exists() est un anachronisme et n'existe que pour des raisons historiques. Il ne devrait presque jamais y avoir de raison de l’utiliser dans votre propre code.

    En particulier, vérifier si un fichier existe avant de l'ouvrir est un anti-motif qui vous rend vulnérable aux conditions de concurrence: un autre processus peut supprimer le fichier entre les appels à fs.exists() et fs.open(). Il suffit d'ouvrir le fichier et de gérer l'erreur quand il n'y en a pas.

    Comme nous parlons d'un répertoire plutôt que d'un fichier, ce conseil implique que vous devez simplement appeler inconditionnellement mkdir et ignorer EEXIST.

  3. En général, vous devriez éviter les méthodes * Sync. Ils bloquent, ce qui signifie absolument que rien d’autre dans votre programme ne peut arriver pendant que vous allez sur le disque. Il s’agit d’une opération très coûteuse et le temps qu’il prend brise l’hypothèse de base de la boucle d’événements du noeud.

    Les méthodes * Sync sont généralement bien dans les scripts rapides à usage unique (ceux qui font une chose, puis se terminent), mais ne devraient presque jamais être utilisées lorsque vous écrivez un serveur: votre serveur sera incapable de répondre à qui que ce soit pendant toute la durée des demandes d'E/S. Si plusieurs demandes de client nécessitent des opérations d'E/S, votre serveur s'arrête très rapidement.


    La seule fois où j'envisagerais d'utiliser les méthodes * Sync dans une application serveur est une opération qui se produit une fois (et une seule fois), au démarrage. Par exemple, requiretilise en réalité readFileSync pour charger des modules.

    Même dans ce cas, vous devez rester prudent, car de nombreuses E/S synchrones peuvent ralentir inutilement le temps de démarrage de votre serveur.


    Au lieu de cela, vous devez utiliser les méthodes d'E/S asynchrones.

Donc, si nous mettons ensemble ces conseils, nous obtenons quelque chose comme ceci:

function ensureExists(path, mask, cb) {
    if (typeof mask == 'function') { // allow the `mask` parameter to be optional
        cb = mask;
        mask = 0777;
    }
    fs.mkdir(path, mask, function(err) {
        if (err) {
            if (err.code == 'EEXIST') cb(null); // ignore the error if the folder already exists
            else cb(err); // something else went wrong
        } else cb(null); // successfully created folder
    });
}

Et on peut l'utiliser comme ça:

ensureExists(__dirname + '/upload', 0744, function(err) {
    if (err) // handle folder creation error
    else // we're all good
});

Bien sûr, cela ne représente pas les cas Edge comme

  • Que se passe-t-il si le dossier est supprimé pendant l'exécution de votre programme? (en supposant que vous vérifiez seulement qu'il existe une fois au démarrage)
  • Que se passe-t-il si le dossier existe déjà mais avec les autorisations incorrectes?
170
josh3736

J'ai trouvé et npm module qui fonctionne comme un charme pour cela. Il suffit simplement de faire un mkdir récursif en cas de besoin, comme un "mkdir -p".

https://www.npmjs.com/package/mkdirp

40
Toni Gamez

Juste au cas où quelqu'un serait intéressé par la version en une ligne. :)

//or in TypeScript: import * as fs from 'fs';
const fs = require('fs');
!fs.existsSync(dir) && fs.mkdirSync(dir);
21
LeOn - Han Li

Vous pouvez simplement utiliser mkdir et récupérer l'erreur si le dossier existe.
Ceci est asynchrone (donc meilleure pratique) et sûr.

fs.mkdir('/path', err => { 
    if (err && err.code != 'EEXIST') throw 'up'
    .. safely do your stuff here  
    })

(Ajoutez éventuellement un deuxième argument avec le mode.)


D'autres pensées:

  1. Vous pouvez alors utiliser ou attendre en utilisant native promisify .

    const util = require('util'), fs = require('fs');
    const mkdir = util.promisify(fs.mkdir);
    var myFunc = () => { ..do something.. } 
    
    mkdir('/path')
        .then(myFunc)
        .catch(err => { if (err.code != 'EEXIST') throw err; myFunc() })
    
  2. Vous pouvez créer votre propre méthode de promesse, quelque chose comme (non testé):

    let mkdirAsync = (path, mode) => new Promise(
       (resolve, reject) => mkdir (path, mode, 
          err => (err && err.code !== 'EEXIST') ? reject(err) : resolve()
          )
       )
    
  3. Pour la vérification synchrone, vous pouvez utiliser:

    fs.existsSync(path) || fs.mkdirSync(path)
    
  4. Ou vous pouvez utiliser une bibliothèque, les deux plus populaires étant

    • mkdirp (ne fait que des dossiers)
    • fsextra (super-ensembles fs, ajoute beaucoup de choses utiles)
15
SamGoody

La méthode mkdir a la capacité de créer récursivement tous les répertoires d’un chemin qui n’existent pas et d’ignorer ceux qui existent.

À partir de la documentation sur les nœuds 10/11 :

// Creates /tmp/a/Apple, regardless of whether `/tmp` and /tmp/a exist.
fs.mkdir('/tmp/a/Apple', { recursive: true }, (err) => {
    if (err) throw err;
});

REMARQUE: vous devez d'abord importer le module intégré fs.

Voici maintenant un exemple un peu plus robuste qui exploite les modules ES natifs (avec l'indicateur activé et l'extension .mjs), gère les chemins d'accès non racine et les comptes de chemins d'accès complets:

import fs from 'fs';
import path from 'path';

createDirectories(pathname) {
   const __dirname = path.resolve();
   pathname = pathname.replace(/^\.*\/|\/?[^\/]+\.[a-z]+|\/$/g, ''); // Remove leading directory markers, and remove ending /file-name.extension
   fs.mkdir(path.resolve(__dirname, pathname), { recursive: true }, e => {
       if (e) {
           console.error(e);
       } else {
           console.log('Success');
       }
    });
}

Vous pouvez l'utiliser comme createDirectories('/components/widget/widget.js');.

Et bien sûr, vous souhaiterez probablement obtenir plus de fantaisie en utilisant des promesses avec async/wait pour exploiter la création de fichier de manière plus lisible de manière synchrone lors de la création des répertoires; mais, cela dépasse la portée de la question.

13
bit-less

La meilleure solution consisterait à utiliser le module npm appelé node-fs-extra . Il a une méthode appelée mkdir qui crée le répertoire que vous avez mentionné. Si vous indiquez un chemin de répertoire long, les dossiers parent seront automatiquement créés. Le module est un super ensemble de npm module fs, vous pouvez donc utiliser toutes les fonctions de fs également si vous ajoutez ce module.

10
Abdul Vajid

Avec le package fs-extra , vous pouvez le faire avec n one-liner :

const fs = require('fs-extra');

const dir = '/tmp/this/path/does/not/exist';
fs.ensureDirSync(dir);
6
galki
var dir = 'path/to/dir';
try {
  fs.mkdirSync(dir);
} catch(e) {
  if (e.code ~= 'EEXIST') throw e;
}
6
Ping.Goblue

Je voudrais ajouter un refactor TypeScript Promise de réponse de josh3736 .

Il fait la même chose et a les mêmes cas Edge, il arrive juste d'utiliser Promises, les typedefs TypeScript et fonctionne avec "use strict".

// https://en.wikipedia.org/wiki/File_system_permissions#Numeric_notation
const allRWEPermissions = parseInt("0777", 8);

function ensureFilePathExists(path: string, mask: number = allRWEPermissions): Promise<void> {
    return new Promise<void>(
        function(resolve: (value?: void | PromiseLike<void>) => void,
            reject: (reason?: any) => void): void{
            mkdir(path, mask, function(err: NodeJS.ErrnoException): void {
                if (err) {
                    if (err.code === "EEXIST") {
                        resolve(null); // ignore the error if the folder already exists
                    } else {
                        reject(err); // something else went wrong
                    }
                } else {
                    resolve(null); // successfully created folder
                }
            });
    });
}
3
Nathan Cooper
    var filessystem = require('fs');
    var dir = './path/subpath/';

    if (!filessystem.existsSync(dir)){
        filessystem.mkdirSync(dir);
    }else
    {
        console.log("Directory already exist");
    }

Cela peut vous aider :)

3
Vishnu S Babu

Vous pouvez utiliser node Système de fichiers commande fs.stat pour vérifier si dir existe et fs.mkdir pour créer un répertoire avec rappel, ou fs.mkdirSync pour créer un répertoire sans rappel, comme dans l'exemple suivant:

//first require fs
const fs = require('fs');

// Create directory if not exist (function)
const createDir = (path) => {
    // check if dir exist
    fs.stat(path, (err, stats) => {
        if (stats.isDirectory()) {
            // do nothing
        } else {
            // if the given path is not a directory, create a directory
            fs.mkdirSync(path);
        }
    });
};
1
majid jiji

Voici une petite fonction pour créer de manière récurrente des répertoires:

const createDir = (dir) => {
  // This will create a dir given a path such as './folder/subfolder' 
  const splitPath = dir.split('/');
  splitPath.reduce((path, subPath) => {
    let currentPath;
    if(subPath != '.'){
      currentPath = path + '/' + subPath;
      if (!fs.existsSync(currentPath)){
        fs.mkdirSync(currentPath);
      }
    }
    else{
      currentPath = subPath;
    }
    return currentPath
  }, '')
}
1
MrBlenny

ENOENT: aucun fichier ou répertoire de ce type, mkdir './assets/

Solution

// const fs = require('fs') in javascript
// import * as fs from "fs" in TypeScript
// import fs from "fs" in TypeScript

!fs.existsSync(`./assets/`) && fs.mkdirSync(`./assets/`, { recursive: true })
0
WasiF

Utiliser async/wait:

const mkdirP = async (directory) => {
  try {
    return await fs.mkdirAsync(directory);
  } catch (error) {
    if (error.code != 'EEXIST') {
      throw e;
    }
  }
};

Vous aurez besoin de promisify fs:

import nodeFs from 'fs';
import bluebird from 'bluebird';

const fs = bluebird.promisifyAll(nodeFs);
0
sdgfsdh