web-dev-qa-db-fra.com

Node.js créer un dossier ou utiliser un fichier existant

J'ai déjà lu la documentation de Node.js et, sauf si quelque chose m'échappe, elle ne dit pas ce que les paramètres contiennent dans certaines opérations, en particulier fs.mkdir() . Comme vous pouvez le constater dans la documentation, ce n’est pas beaucoup.

Actuellement, j'ai ce code, qui tente de créer un dossier ou d'utiliser un dossier existant à la place:

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

Mais je me demande si c'est la bonne façon de le faire? La vérification du code EEXIST est-elle la bonne façon de savoir que le dossier existe déjà? Je sais que je peux faire fs.stat() avant de créer le répertoire, mais il y aurait déjà deux occurrences dans le système de fichiers.

Deuxièmement, existe-t-il une documentation complète ou au moins plus détaillée de Node.js contenant des détails sur les objets d'erreur, les paramètres, etc.?.

156
Joseph

Une bonne façon de faire est d’utiliser mkdirp module.

$ npm install mkdirp

Utilisez-le pour exécuter une fonction nécessitant le répertoire. Le rappel est appelé après la création du chemin ou s'il existe déjà. L'erreur err est définie si mkdirp n'a pas pu créer le chemin du répertoire.

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

    // path exists unless there was an error

});
222
Teemu Ikonen

En utilisant un try {} catch {}, vous pouvez y parvenir très gracieusement sans rencontrer de condition de concurrence critique:

Tolérant aux pannes fs.mkdirSync(dirPath)

const mkdirSync = function (dirPath) {
  try {
    fs.mkdirSync(dirPath)
  } catch (err) {
    if (err.code !== 'EEXIST') throw err
  }
}

Remarque: dirPath est utilisé comme argument à la place de path, comme dans la documentation officielle du Node's fs.mkdirSync, afin d'éviter toute confusion avec le module de chemin d'accès standard du nœud.

Explication

Le nœud essaiera de créer le répertoire et lèvera une exception s'il rencontre une exception le faisant. Dans la clause catch {}, nous continuons l'exécution du script comme si rien ne s'était passé si le code d'erreur est EEXIST, ce qui signifie que le répertoire existe. Si le code d'erreur n'est pas EEXIST cependant, nous devrions lancer une erreur, car nous avons probablement affaire à une exception de système de fichiers telle que EACCES (permission refusée).

Comme il n’ya pas de temps mort entre la vérification de l’existence et la création du répertoire, nous évitons les situations de concurrence; ceci ne peut cependant être vrai que lorsque vous utilisez la version synchrone (donc fs.mkdir() ne fonctionnerait pas), mais les opérations de système de fichiers destructives telles que mkdir ne devraient de toute façon être utilisées que de manière synchrone.

Edit: Depuis, j’ai trouvé le moyen d’adapter le même concept au fs.mkdir asynchrone que vous pouvez trouver dans ce Gist of my

Exemples

Créons les répertoires ./first/second/third et ./first/second/fourth, étant donné:

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

const mkdirSync = function (dirPath) {
  try {
    fs.mkdirSync(dirPath)
  } catch (err) {
    if (err.code !== 'EEXIST') throw err
  }
}

Utilisation linéaire

Avec la fonction encapsulée ci-dessus, vous pouvez vous assurer que les répertoires existent et les créer facilement.

mkdirSync(path.resolve('./first'))
mkdirSync(path.resolve('./first/second'))
mkdirSync(path.resolve('./first/second/third'))
mkdirSync(path.resolve('./first/second')) // To demonstrate fault tolerance
mkdirSync(path.resolve('./first/second/fourth'))

Remarque: vous devez toujours vous assurer que chaque partie du chemin de répertoire existe. Appelez directement mkdirSync(path.resolve('./first/second/third')) sans vous assurer que ./first et ./first/second existerait toujours une exception.

Utilisation récursive comme le mkdir -p d'UNIX

Afin de contourner l'inconvénient mentionné ci-dessus, vous pouvez envelopper notre mkdirSync() à tolérance de pannes dans une fonction récursive qui garantira que chaque partie du chemin existe:

const mkdirpSync = function (dirPath) {
  const parts = dirPath.split(path.sep)

  // For every part of our path, call our wrapped mkdirSync()
  // on the full path until and including that part
  for (let i = 1; i <= parts.length; i++) {
    mkdirSync(path.join.apply(null, parts.slice(0, i)))
  }
}

// You can now directly create the two target directories
mkdirpSync('first/second/third')
mkdirpSync('first/second/fourth')
147
Christophe Marois

Si vous voulez une doublure rapide et sale, utilisez ceci:

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

Les documents de node.js pour fs.mkdir sont généralement reportés à la page de manuel Linux de mkdir(2) . Cela indique que EEXIST sera également indiqué si le chemin existe mais qu’il ne s’agit pas d’un répertoire qui crée un casier difficile si vous suivez cette route.

Vous feriez mieux d’appeler fs.stat qui vous dira si le chemin existe et s’il s’agit d’un répertoire dans un seul appel. Pour (ce que je suppose) le cas normal où le répertoire existe déjà, il ne s'agit que d'un simple hit de système de fichiers.

Ces méthodes de module fs sont des encapsuleurs légers autour des API C natives. Vous devez donc consulter les pages de manuel référencées dans la documentation de node.js pour plus de détails.

26
JohnnyHK

Vous pouvez utiliser ceci:

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");
        }
    });
}
21
Raugaral

Je propose une solution sans modules (accumuler des modules n'est jamais recommandé pour la maintenabilité surtout pour les petites fonctions pouvant être écrites en quelques lignes ...):

MISE À JOUR 2019:

// 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');
4
Liberateur

Vous pouvez également utiliser fs-extra , qui fournit beaucoup d’opérations sur les fichiers fréquemment utilisées.

Exemple de code:

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')

docs ici: https://github.com/jprichardson/node-fs-extra#mkdirsdir-callback

3
Geng Jiawen

Voici le code ES6 que j'utilise pour créer un répertoire (lorsqu'il n'existe pas):

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}`)
});

Remarque:

  • Au début de la fonction createDirectory, je normalise le chemin pour garantir que le type de séparateur de chemin du système d’exploitation sera utilisé de manière cohérente (par exemple, cela transformera C:\directory/test en C:\directory\test (sous Windows).
  • fs.exists est deprecated , c’est pourquoi j’utilise fs.stat pour vérifier si le répertoire existe déjà
  • Si un répertoire n'existe pas, le code d'erreur sera ENOENT (E rror NO ENT ry)
  • Le répertoire lui-même sera créé avec fs.mkdir
  • Je préfère la fonction asynchrone fs.mkdir à son homologue bloquant fs.mkdirSync et, en raison du wrapping Promise, il sera garanti que le chemin du répertoire ne sera retourné qu'une fois le répertoire créé avec succès.
3
Benny Neugebauer

Vous feriez mieux de ne pas compter les hits du système de fichiers pendant que vous codiez en Javascript, à mon avis . Cependant, (1) stat & mkdir et (2) mkdir et cocher (ou supprimer) le code d'erreur, les deux méthodes sont correctes façons de faire ce que vous voulez.

3
Chul-Woong Yang

créer un répertoire de noms dynamiques pour chaque utilisateur ... utilisez ce code

***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
Adiii

Juste comme une alternative plus récente à La réponse de Teemu Ikonen , qui est très simple et facilement lisible, consiste à utiliser la méthode ensureDir du package fs-extra .

Il peut non seulement être utilisé en remplacement flagrant du module fs intégré, mais dispose également de nombreuses autres fonctionnalités, en plus des fonctionnalités du package fs.

La méthode ensureDir, comme son nom l’indique, garantit l’existence du répertoire. Si la structure de répertoires n'existe pas, elle est créée. Comme mkdir -p. Pas seulement le dossier de fin, mais tout le chemin est créé s'il n'existe pas déjà.

celui fourni ci-dessus en est la version async. Il dispose également d'une méthode synchrone pour effectuer cela sous la forme de la méthode ensureDirSync .

0
Rai

La réponse de Raugaral mais avec la fonctionnalité -p. Moche, mais ça marche:

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
user8675309