Wie schreibe ich eine Datei, wenn der übergeordnete Ordner nicht vorhanden ist?

93

Ich muss eine Datei in den folgenden Pfad schreiben:

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

Aber der '/folder1/folder2'Pfad existiert möglicherweise nicht. Also bekomme ich folgenden Fehler:

message = ENOENT, öffne /folder1/folder2/file.txt

Wie kann ich Inhalte auf diesen Pfad schreiben?

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

Antworten:

127

Verwenden Sie mkdirp in Kombination mit path.dirnamefirst.

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

Wenn der gesamte Pfad bereits vorhanden ist, mkdirpist ein Noop. Andernfalls werden alle fehlenden Verzeichnisse für Sie erstellt.

Dieses Modul macht, was Sie wollen: https://npmjs.org/package/writefile . Habe es beim googeln nach "writefile mkdirp" bekommen. Dieses Modul gibt ein Versprechen zurück, anstatt einen Rückruf entgegenzunehmen. Lesen Sie daher zuerst eine Einführung in Versprechen. Es könnte die Dinge für Sie tatsächlich komplizieren.

Die Funktion, die ich gegeben habe, funktioniert auf jeden Fall.

Myrne Stol
quelle
Wenn wir also warten möchten, bis es abgeschlossen ist, müssen wir alles danach in den Rückruf einfügen? Gibt es einen anderen Weg?
Peter
@pete Wenn Sie Babel verwenden, können Sie mit async gehen / warten wie folgt: gist.github.com/lucasreppewelander/…
Lucas Reppe Welander
10
Verwenden Sie rekursiv:fs.promises.mkdir(path.dirname(file), {recursive: true}).then(x => fs.promises.writeFile(file, data))
Offenso
27

Ich finde, dass der einfachste Weg, dies zu tun, darin besteht, die outputFile () -Methode aus dem fs-extra- Modul zu verwenden.

Fast das gleiche wie writeFile (dh es wird überschrieben), außer dass das übergeordnete Verzeichnis erstellt wird, wenn es nicht vorhanden ist. Optionen sind das, was Sie an fs.writeFile () übergeben würden.

Beispiel:

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

Es hat auch vielversprechende Unterstützung in diesen Tagen!.

tkarls
quelle
19

Am einfachsten ist es vielleicht, wenn Sie einfach das fs-path npm-Modul verwenden.

Ihr Code würde dann so aussehen:

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

Bearbeiten

NodeJS Version 10 hat eine native Unterstützung für beide hinzugefügt mkdirund mkdirSyncum den übergeordneten Director rekursiv mit recursive: trueder folgenden Option zu erstellen :

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

Und wenn Sie es vorziehen fs Promises API, können Sie schreiben

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

Ursprüngliche Antwort

Erstellen Sie die übergeordneten Verzeichnisse rekursiv, wenn sie nicht vorhanden sind! ( Null Abhängigkeiten )

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

Verwendung

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

Demo

Versuch es!

Erklärungen

  • [UPDATE] Diese Lösung Griffe plattformspezifische Fehler wie EISDIRfür Mac und EPERMund EACCESfür Windows.
  • Diese Lösung verarbeitet sowohl relative als auch absolute Pfade.
  • Bei relativen Pfaden werden Zielverzeichnisse im aktuellen Arbeitsverzeichnis erstellt (aufgelöst). Übergeben Sie, um sie relativ zum aktuellen Skriptverzeichnis aufzulösen {isRelativeToScript: true}.
  • Verwenden path.sepund path.resolve()nicht nur /Verketten, um plattformübergreifende Probleme zu vermeiden.
  • Verwenden fs.mkdirSyncund Behandeln des Fehlers mit, try/catchwenn er ausgelöst wird, um die Rennbedingungen zu behandeln: Ein anderer Prozess kann die Datei zwischen den Aufrufen von fs.existsSync()und hinzufügen fs.mkdirSync()und eine Ausnahme verursachen.
    • Der andere Weg, dies zu erreichen, könnte darin bestehen, zu überprüfen, ob eine Datei vorhanden ist, und sie dann zu erstellen, d if (!fs.existsSync(curDir) fs.mkdirSync(curDir);. H. Dies ist jedoch ein Anti-Pattern, das den Code für Rennbedingungen anfällig macht.
  • Benötigt Node v6 und neuer, um die Destrukturierung zu unterstützen. (Wenn Sie Probleme bei der Implementierung dieser Lösung mit alten Node-Versionen haben, hinterlassen Sie mir einfach einen Kommentar.)
Mouneer
quelle
3

Sie können verwenden

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

statsist eine fs.StatsArt von Objekt, das Sie überprüfen können stats.isDirectory(). Abhängig von der Prüfung von errund statskönnen Sie etwas tun fs.mkdir( ... )oder einen Fehler werfen.

Referenz

Update: Die Kommas im Code wurden korrigiert.

MikeD
quelle
Ich kann also keine Datei mit dem Befehl sibgle in nodejs schreiben?
Erik
2

Hier ist meine benutzerdefinierte Funktion zum rekursiven Erstellen von Verzeichnissen (ohne externe Abhängigkeiten):

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);
math_lab3.ca
quelle
2

Hier ist meine Funktion, die in Knoten 10.12.0 funktioniert. Hoffe das wird helfen.

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!');
        });
    }
Kailash
quelle
1

Mit node-fs-extra können Sie dies problemlos tun.

Es installieren

npm install --save fs-extra

Verwenden Sie dann die outputFile- Methode anstelle von 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!');
  }
})
Muhammad Numan
quelle
0

Hier ist ein Teil von Myrne Stols Antwort, die als separate Antwort aufgeschlüsselt ist:

Dieses Modul macht, was Sie wollen: https://npmjs.org/package/writefile . Habe es beim googeln nach "writefile mkdirp" bekommen. Dieses Modul gibt ein Versprechen zurück, anstatt einen Rückruf entgegenzunehmen. Lesen Sie daher zuerst eine Einführung in Versprechen. Es könnte die Dinge für Sie tatsächlich komplizieren.

David Braun
quelle
0
let name = "./new_folder/" + file_name + ".png";
await driver.takeScreenshot().then(
  function(image, err) {
    require('mkdirp')(require('path').dirname(name), (err) => {
      require('fs').writeFile(name, image, 'base64', function(err) {
        console.log(err);
      });
    });
  }
);
Luat Do.
quelle
Nur-Code-Antworten gelten als minderwertig: Stellen Sie sicher, dass Sie erklären, was Ihr Code tut und wie er das Problem löst. Es wird sowohl dem Fragesteller als auch zukünftigen Lesern helfen, wenn Sie Ihrem Beitrag weitere Informationen hinzufügen können. Siehe Erklären vollständig
codebasierter