126 votes

Comment écrire un fichier si le dossier parent n'existe pas ?

J'ai besoin d'écrire un fichier dans le chemin suivant :

fs.writeFile('/folder1/folder2/file.txt', 'content', function () {…});

Mais '/folder1/folder2' Le chemin peut ne pas exister. J'obtiens donc l'erreur suivante :

message=ENOENT, ouvrir /dossier1/dossier2/file.txt

Comment puis-je rédiger du contenu dans ce sens ?

3 votes

fs.promises.mkdir(path.dirname('/folder1/folder2/file.txt'), {recursive: true}).then(x => fs.promises.writeFile('/folder1/folder2/file.txt', 'content'))

164voto

Meryn Stol Points 4099

A partir de Node v10, ceci est intégré dans la fonction fs.mkdir que nous pouvons utiliser en combinaison avec la fonction path.dirname :

var fs = require('fs');
var getDirName = require('path').dirname;

function writeFile(path, contents, cb) {
  fs.mkdir(getDirName(path), { recursive: true}, function (err) {
    if (err) return cb(err);

    fs.writeFile(path, contents, cb);
  });
}

Pour les anciennes versions, vous pouvez utiliser mkdirp :

var mkdirp = require('mkdirp');
var fs = require('fs');
var getDirName = require('path').dirname;

function writeFile(path, contents, cb) {
  mkdirp(getDirName(path), function (err) {
    if (err) return cb(err);

    fs.writeFile(path, contents, cb);
  });
}

Si le chemin entier existe déjà, mkdirp est un non sens. Sinon, il crée tous les répertoires manquants pour vous.

Ce module fait ce que vous voulez : https://npmjs.org/package/writefile . Je l'ai trouvé en cherchant sur Google "writefile mkdirp". Ce module retourne une promesse au lieu de prendre un callback, donc assurez-vous de lire une introduction aux promesses d'abord. Cela pourrait en fait compliquer les choses pour vous.

La fonction que j'ai donnée fonctionne dans tous les cas.

0 votes

Donc, si nous voulons attendre qu'il se termine, nous devons mettre tout ce qui se trouve après dans le callback ? Y a-t-il un autre moyen ?

0 votes

@pete si vous utilisez babel, vous pouvez utiliser async/await comme ce gist : gist.github.com/lucasreppewelander/

21 votes

Utiliser la récursivité : fs.promises.mkdir(path.dirname(file), {recursive: true}).then(x => fs.promises.writeFile(file, data))

40voto

Mouneer Points 4273

Modifier

Version de NodeJS 10.12.0 a ajouté un support natif pour les deux mkdir y mkdirSync pour créer le directeur parent de manière récursive avec recursive: true comme suit :

fs.mkdirSync(targetDir, { recursive: true });

Et si vous préférez fs Promises API vous pouvez écrire

fs.promises.mkdir(targetDir, { recursive: true });

Réponse originale

Créez les répertoires parents récursivement s'ils n'existent pas ! ( Aucune dépendance )

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

function mkDirByPathSync(targetDir, { isRelativeToScript = false } = {}) {
  const sep = path.sep;
  const initDir = path.isAbsolute(targetDir) ? sep : '';
  const baseDir = isRelativeToScript ? __dirname : '.';

  return targetDir.split(sep).reduce((parentDir, childDir) => {
    const curDir = path.resolve(baseDir, parentDir, childDir);
    try {
      fs.mkdirSync(curDir);
    } catch (err) {
      if (err.code === 'EEXIST') { // curDir already exists!
        return curDir;
      }

      // To avoid `EISDIR` error on Mac and `EACCES`-->`ENOENT` and `EPERM` on Windows.
      if (err.code === 'ENOENT') { // Throw the original parentDir error on curDir `ENOENT` failure.
        throw new Error(`EACCES: permission denied, mkdir '${parentDir}'`);
      }

      const caughtErr = ['EACCES', 'EPERM', 'EISDIR'].indexOf(err.code) > -1;
      if (!caughtErr || caughtErr && curDir === path.resolve(targetDir)) {
        throw err; // Throw if it's just the last created dir.
      }
    }

    return curDir;
  }, initDir);
}

Utilisation

// Default, make directories relative to current working directory.
mkDirByPathSync('path/to/dir');

// Make directories relative to the current script.
mkDirByPathSync('path/to/dir', {isRelativeToScript: true});

// Make directories with an absolute path.
mkDirByPathSync('/path/to/dir');

Démo

Essayez-le !

Explications

  • [MISE À JOUR] Cette solution permet de traiter les erreurs spécifiques à la plate-forme, comme EISDIR pour Mac et EPERM y EACCES pour Windows.
  • Cette solution permet de gérer à la fois relativa y absolu chemins.
  • Dans le cas de chemins relatifs, les répertoires cibles seront créés (résolus) dans le répertoire de travail actuel. Pour les résoudre relativement au répertoire courant script, passez {isRelativeToScript: true} .
  • Utilisation de path.sep y path.resolve() pas seulement / concaténation, afin d'éviter les problèmes de multi-plateforme.
  • Utilisation de fs.mkdirSync et de traiter l'erreur avec try/catch si elle est lancée pour gérer les conditions de course : un autre processus peut ajouter le fichier entre les appels à fs.existsSync() y fs.mkdirSync() et provoque une exception.
    • L'autre moyen d'y parvenir pourrait être de vérifier si un fichier existe puis de le créer, c'est-à-dire if (!fs.existsSync(curDir) fs.mkdirSync(curDir); . Mais il s'agit d'un anti-modèle qui rend le code vulnérable aux conditions de course.
  • Nécessite Node v6 et plus récents pour supporter la déstructuration. (Si vous avez des problèmes pour mettre en œuvre cette solution avec les anciennes versions de Node, laissez-moi un commentaire).

37voto

tkarls Points 162

Je trouve que le moyen le plus simple de le faire est d'utiliser la fonction outputFile () de la méthode fs-extra module.

Presque la même chose que writeFile (c'est-à-dire qu'il écrase), sauf que si le répertoire parent n'existe pas, il est créé. Les options sont celles que vous passeriez à fs.writeFile().

Exemple :

var fs = require('fs-extra');
var file = '/tmp/this/path/does/not/exist/file.txt'

fs.outputFile(file, 'hello!', function (err) {
    console.log(err); // => null

    fs.readFile(file, 'utf8', function (err, data) {
        console.log(data); // => hello!
    });
});

Il est également doté d'un support de promesse de sortie de boîte ces jours-ci !

22voto

kevincoleman Points 464

Peut-être le plus simplement, vous pouvez simplement utiliser le fs-path module npm.

Votre code sera alors le suivant :

var fsPath = require('fs-path');

fsPath.writeFile('/folder1/folder2/file.txt', 'content', function(err){
  if(err) {
    throw err;
  } else {
    console.log('wrote a file like DaVinci drew machines');
  }
});

5voto

Muhammad Numan Points 71

Avec node-fs-extra, vous pouvez le faire facilement.

Installez-le

npm install --save fs-extra

Utilisez ensuite le outputFile au lieu de writeFileSync

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

fs.outputFile('tmp/test.txt', 'Hey there!', err => {
  if(err) {
    console.log(err);
  } else {
    console.log('The file was saved!');
  }
})

0 votes

Node est capable de le faire nativement depuis 2018. fs-extra est utile si vous avez besoin de toutes les librairies qu'il contient, mais si vous avez besoin de juste besoin mkdir -p qui est intégrée dans fs.mkdir de Node depuis la version 10.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X