web-dev-qa-db-fra.com

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

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

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

 });

Mais '/folder1/folder2' chemin ne peut pas exister. Donc j'obtiens l'erreur suivante:

 message=ENOENT, open /folder1/folder2/file.txt

Comment puis-je écrire du contenu sur ce chemin?

73
Erik

Utilisez mkdirp en combinaison avec path.dirname d'abord.

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 tout le chemin existe déjà, mkdirp est un noop. Sinon, il crée tous les répertoires manquants pour vous.

Ce module fait ce que vous voulez: https://npmjs.org/package/writefile . Vous l'avez quand googler pour "writefile mkdirp". Ce module renvoie une promesse au lieu de prendre un rappel. Assurez-vous donc de lire quelques introductions aux promesses. Cela pourrait compliquer les choses pour vous.

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

114
Myrne Stol

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

Presque identique à writeFile (c’est-à-dire qu’il écrase), sauf que si le répertoire parent n’existe pas, il est créé. les options sont ce que vous transmettriez à 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 a également promis un soutien hors de la boîte ces jours-ci!.

19
tkarls

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

Votre code ressemblerait alors à:

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');
  }
});
17
kevincoleman

Modifier

NodeJS version 10 a ajouté un support natif pour les deux mkdir et mkdirSync afin de créer le directeur parent de manière récursive avec l'option _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 de manière récursive s'ils n'existent pas! ( Zéro 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);
}
_

Usage

_// 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!

Des explications

  • [UPDATE] Cette solution gère les erreurs spécifiques à la plate-forme, telles que EISDIR pour Mac et EPERM et EACCES pour Windows.
  • Cette solution gère les deux chemins relatifs et absolus .
  • 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 par rapport au répertoire de script actuel, transmettez _{isRelativeToScript: true}_.
  • Utilisation de la concaténation _path.sep_ et path.resolve() , et pas seulement _/_, pour éviter les problèmes multi-plateformes.
  • Utiliser _fs.mkdirSync_ et gérer l'erreur avec _try/catch_ s'il est levé pour gérer les conditions de concurrence: un autre processus peut ajouter le fichier entre les appels à fs.existsSync() et 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, à savoir, if (!fs.existsSync(curDir) fs.mkdirSync(curDir);. Mais c'est un anti-modèle qui laisse le code vulnérable aux conditions de concurrence.
  • Requiert nœud v6 et plus récent pour prendre en charge la déstructuration. (Si vous rencontrez des problèmes pour implémenter cette solution avec d'anciennes versions de Node, laissez-moi un commentaire.)
7
Mouneer

Vous pouvez utiliser

fs.stat('/folder1/folder2', function(err, stats){ ... });

stats est un type d'objet fs.Stats, vous pouvez vérifier stats.isDirectory(). Selon l'examen de err et stats, vous pouvez faire quelque chose, fs.mkdir( ... ) ou générer une erreur.

référence

Mise à jour: Correction des virgules dans le code.

3
MikeD

Voici ma fonction personnalisée pour créer de manière récursive des répertoires (sans dépendance externe):

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

var myMkdirSync = function(dir){
    if (fs.existsSync(dir)){
        return
    }

    try{
        fs.mkdirSync(dir)
    }catch(err){
        if(err.code == 'ENOENT'){
            myMkdirSync(path.dirname(dir)) //create parent dir
            myMkdirSync(dir) //create dir
        }
    }
}

myMkdirSync(path.dirname(filePath));
var file = fs.createWriteStream(filePath);
2
math_lab3.ca

Voici ma fonction qui fonctionne dans Node 10.12.0. J'espère que cela vous aidera.

const fs = require('fs');
function(dir,filename,content){
        fs.promises.mkdir(dir, { recursive: true }).catch(error => { console.error('caught exception : ', error.message); });
        fs.writeFile(dir+filename, content, function (err) {
            if (err) throw err;
            console.info('file saved!');
        });
    }
1
Kailash

Voici une partie de la réponse de Myrne Stol présentée séparément:

Ce module fait ce que vous voulez: https://npmjs.org/package/writefile . Vous l'avez quand googler pour "writefile mkdirp". Ce module renvoie une promesse au lieu de prendre un rappel. Assurez-vous donc de lire quelques introductions aux promesses. Cela pourrait compliquer les choses pour vous.

0
David Braun