Erstellen Sie ein Verzeichnis beim Schreiben in eine Datei in Node.js.


134

Ich habe an Node.js herumgebastelt und ein kleines Problem gefunden. Ich habe ein Skript, das sich in einem Verzeichnis namens befindet data. Ich möchte, dass das Skript einige Daten in eine Datei in einem Unterverzeichnis innerhalb des dataUnterverzeichnisses schreibt . Ich erhalte jedoch den folgenden Fehler:

{ [Error: ENOENT, open 'D:\data\tmp\test.txt'] errno: 34, code: 'ENOENT', path: 'D:\\data\\tmp\\test.txt' }

Der Code lautet wie folgt:

var fs = require('fs');
fs.writeFile("tmp/test.txt", "Hey there!", function(err) {
    if(err) {
        console.log(err);
    } else {
        console.log("The file was saved!");
    }
}); 

Kann mir jemand helfen, herauszufinden, wie Node.js die Verzeichnisstruktur erstellen kann, wenn sie nicht zum Schreiben in eine Datei beendet wird?


1
fs.promises.mkdir(path.dirname("tmp/test.txt"), {recursive: true}).then(x => fs.promises.writeFile("tmp/test.txt", "Hey there!"))
Offenso

Antworten:


127

Knoten> 10.12.0

fs.mkdir akzeptiert jetzt eine { recursive: true }Option wie folgt :

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

oder mit einem Versprechen:

fs.promises.mkdir('/tmp/a/apple', { recursive: true }).catch(console.error);

Knoten <= 10.11.0

Sie können dies mit einem Paket wie mkdirp oder fs-extra lösen . Wenn Sie kein Paket installieren möchten, lesen Sie bitte die Antwort von Tiago Peres França unten.


4
Das ist die, mit der ich gehe ... diese Statistiken haben mich überzeugt.
Aran Mulholland

Beachten Sie, dass fs.promisesnoch experimentell ist nodejs.org/dist/latest-v10.x/docs/api/…
lasec0203

132

Wenn Sie kein zusätzliches Paket verwenden möchten, können Sie vor dem Erstellen Ihrer Datei die folgende Funktion aufrufen:

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

function ensureDirectoryExistence(filePath) {
  var dirname = path.dirname(filePath);
  if (fs.existsSync(dirname)) {
    return true;
  }
  ensureDirectoryExistence(dirname);
  fs.mkdirSync(dirname);
}

2
Dies sollte statSyncanstelle von verwendet werden existsSync, basierend auf stackoverflow.com/questions/4482686/…
GavinR

1
pathist auch ein Paket, das genauso benötigt werden muss fs: var path = require('path')falls sich jemand wundert. Siehe Knotendokumentation .
Rafael Emshoff


6
Es gab einige Verwirrung darüber, ob die Funktion fs.existsSync veraltet ist oder nicht. Nach meinem Verständnis dachte ich zuerst, dass dies der Fall ist, und aktualisierte die Antwort, um dies widerzuspiegeln. Wie aus @zzzzBov hervorgeht, heißt es in der Dokumentation nun eindeutig, dass nur fs.exists veraltet ist und die Verwendung von fs.existsSync weiterhin gültig ist. Aus diesem Grund habe ich den vorherigen Code gelöscht und meine Antwort enthält nur noch die einfachere Lösung (unter Verwendung von fs.existsSync).
Tiago Peres França

1
@chrismarx stellen Sie sich den folgenden Pfad vor: "/home/documents/a/b/c/myfile.txt". "/ home / documents" existiert, alles davor nicht. Wenn "sureDirectoryExistence" zum ersten Mal aufgerufen wird, lautet der Verzeichnisname "/ home / documents / a / b / c". Ich kann fs.mkdirSync (dirname) momentan nicht aufrufen, da "/ home / documents / a / b" ebenfalls nicht existiert. Um das Verzeichnis "c" zu erstellen, muss ich zuerst die Existenz von "/ home / documents / a / b" sicherstellen.
Tiago Peres França

43

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

Es installieren

npm install --save fs-extra

Verwenden Sie dann die outputFileMethode. Die Dokumentation lautet:

Fast dasselbe wie writeFile (dh es wird überschrieben), außer dass das übergeordnete Verzeichnis erstellt wird, wenn es nicht vorhanden ist.

Sie können es auf drei Arten verwenden:

Rückrufstil

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

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

Versprechen verwenden

Wenn Sie Versprechen verwenden , und ich hoffe es, ist dies der Code:

fse.outputFile('tmp/test.txt', 'Hey there!')
   .then(() => {
       console.log('The file was saved!');
   })
   .catch(err => {
       console.error(err)
   });

Version synchronisieren

Wenn Sie eine Synchronisierungsversion wünschen, verwenden Sie einfach diesen Code:

fse.outputFileSync('tmp/test.txt', 'Hey there!')

Eine vollständige Referenz finden Sie in der outputFileDokumentation und in allen von node-fs-extra unterstützten Methoden .


26

Schamloser Plug-Alarm!

Sie müssen nach jedem Verzeichnis in der gewünschten Pfadstruktur suchen und es manuell erstellen, wenn es nicht vorhanden ist. Alle Tools dafür sind bereits im fs-Modul von Node vorhanden, aber Sie können dies alles einfach mit meinem mkpath-Modul tun: https://github.com/jrajav/mkpath


1
Wird dadurch die Datei direkt oder nur die Verzeichnisstruktur erstellt? Ich suche nach einer Lösung, die die Datei zusammen mit der Verzeichnisstruktur beim Erstellen der Datei erstellt.
Hirvesh

Nur die Verzeichnisstruktur. Sie würden zuerst das mkdir / path eingeben und, wenn es keine Fehler gäbe, mit dem Schreiben Ihrer Datei fortfahren. Es wäre einfach genug, eine Funktion zu schreiben, um beides gleichzeitig zu tun, wenn ein vollständiger Pfad zu einer zu schreibenden Datei angegeben wird.
Teilen

1
Tatsächlich war es so einfach, dass ich es in 2 Minuten geschrieben habe . :) (ungetestet)
jrajav

Update: Getestet und bearbeitet, versuchen Sie es erneut, wenn es beim ersten Mal nicht funktioniert hat.
Jrajav

8
@Kiyura Wie unterscheidet sich das von dem weit verbreiteten mkdirp ?
David Weldon

9

Da ich noch keinen Kommentar abgeben kann, veröffentliche ich eine erweiterte Antwort basierend auf der fantastischen Lösung @ tiago-peres-frança (danke!). Sein Code erstellt kein Verzeichnis in einem Fall, in dem nur das letzte Verzeichnis im Pfad fehlt, z. B. lautet die Eingabe "C: / test / abc" und "C: / test" ist bereits vorhanden. Hier ist ein Ausschnitt, der funktioniert:

function mkdirp(filepath) {
    var dirname = path.dirname(filepath);

    if (!fs.existsSync(dirname)) {
        mkdirp(dirname);
    }

    fs.mkdirSync(filepath);
}

1
Dies liegt daran, dass die Lösung von @ tiago einen Dateipfad erwartet . In Ihrem Fall abcwird dies als die Datei interpretiert, für die Sie ein Verzeichnis erstellen müssen. Um auch das abcVerzeichnis zu erstellen , fügen Sie Ihrem Pfad eine Dummy-Datei hinzu, z C:/test/abc/dummy.txt.
Sphinxxx

Verwenden Sie rekursiv:fs.promises.mkdir(path.dirname(file), {recursive: true}).then(x => fs.promises.writeFile(file, data))
Offenso

1
@Offenso ist die beste Lösung, aber nur für Node.js Version 10.12 und höher.
Nickensoul

8

Mein Rat ist: Versuchen Sie, sich nicht auf Abhängigkeiten zu verlassen, wenn Sie dies mit wenigen Codezeilen problemlos tun können

Folgendes möchten Sie in 14 Codezeilen erreichen:

fs.isDir = function(dpath) {
    try {
        return fs.lstatSync(dpath).isDirectory();
    } catch(e) {
        return false;
    }
};
fs.mkdirp = function(dirname) {
    dirname = path.normalize(dirname).split(path.sep);
    dirname.forEach((sdir,index)=>{
        var pathInQuestion = dirname.slice(0,index+1).join(path.sep);
        if((!fs.isDir(pathInQuestion)) && pathInQuestion) fs.mkdirSync(pathInQuestion);
    });
};

1
Wäre die dritte Zeile nicht besser so? return fs.lstatSync(dpath).isDirectory(), was würde sonst passieren, wenn isDirectory () false zurückgibt?
Giorgio Aresu

2
Verwenden Sie rekursiv:fs.promises.mkdir(path.dirname(file), {recursive: true}).then(x => fs.promises.writeFile(file, data))
Offenso

1
@Offenso es wird nicht von einem Knoten 8 unterstützt
Ievgen Naida

2

Ich habe dieses Modul gerade veröffentlicht, weil ich diese Funktionalität brauchte.

https://www.npmjs.org/package/filendir

Es funktioniert wie ein Wrapper um Node.js fs-Methoden. Sie können es also genauso verwenden wie mit fs.writeFileund fs.writeFileSync(sowohl asynchrone als auch synchrone Schreibvorgänge).

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.