1149 Stimmen

Wie man ein Verzeichnis erstellt, wenn es mit Node.js nicht existiert

Ist dies der richtige Weg, um ein Verzeichnis zu erstellen, wenn es nicht existiert?

Es sollte volle Berechtigung für das Skript haben und von anderen lesbar sein.

var dir = __dirname + '/upload';
if (!path.existsSync(dir)) {
    fs.mkdirSync(dir, 0744);
}

2130voto

chovy Punkte 64969

Für einzelne Verzeichnisse:

var fs = require('fs');
var dir = './tmp';

if (!fs.existsSync(dir)){
    fs.mkdirSync(dir);
}

Oder für verschachtelte Verzeichnisse:

var fs = require('fs');
var dir = './tmp/but/then/nested';

if (!fs.existsSync(dir)){
    fs.mkdirSync(dir, { recursive: true });
}

241voto

josh3736 Punkte 130889

Nein, aus mehreren Gründen.

  1. Das Pfad Modul hat keine exists/existsSync Methode. Diese befindet sich im fs Modul. (Vielleicht haben Sie nur einen Tippfehler in Ihrer Frage gemacht?)

  2. Die Dokumentation rät explizit davon ab, exists zu verwenden.

    fs.exists() ist ein Anachronismus und existiert nur aus historischen Gründen. Es sollte fast nie einen Grund geben, es in Ihrem eigenen Code zu verwenden.

    Insbesondere das Überprüfen, ob eine Datei existiert, bevor sie geöffnet wird, ist ein Anti-Muster, das Sie anfällig für Rennbedingungen macht: Ein anderer Prozess kann die Datei zwischen den Aufrufen von fs.exists() und fs.open() entfernen. Öffnen Sie einfach die Datei und behandeln Sie den Fehler, wenn sie nicht vorhanden ist.

    Da wir über ein Verzeichnis und nicht über eine Datei sprechen, bedeutet dieser Rat, dass Sie einfach bedingungslos mkdir aufrufen und EEXIST ignorieren sollten.

  3. Im Allgemeinen sollten Sie die *Sync Methoden vermeiden. Sie sind blockierend, was bedeutet, dass absolut nichts anderes in Ihrem Programm geschehen kann, während Sie auf die Festplatte zugreifen. Dies ist eine sehr teure Operation, und die Zeit, die dafür benötigt wird, bricht die Kernannahme der Ereignisschleife von Node.

    Die *Sync Methoden sind normalerweise in Ein-Zweck-Schnellskripten in Ordnung (solche, die eine Sache tun und dann beenden), sollten aber fast nie verwendet werden, wenn Sie einen Server schreiben: Ihr Server wird während der gesamten Dauer der I/O-Anfragen nicht in der Lage sein, auf jemanden zu antworten. Wenn mehrere Client-Anfragen I/O-Operationen erfordern, wird Ihr Server sehr schnell zum Stillstand kommen.


    Die einzige Zeit, zu der ich in Betracht ziehen würde, *Sync Methoden in einer Serveranwendung zu verwenden, ist eine Operation, die einmalig (und nur einmal) beim Start ausgeführt wird. Zum Beispiel verwendet require tatsächlich readFileSync, um Module zu laden.

    Selbst dann müssen Sie vorsichtig sein, da viele synchrone I/O-Operationen die Startzeit Ihres Servers unnötigerweise verlangsamen können.


    Verwenden Sie stattdessen die asynchronen I/O-Methoden.

Wenn wir all diese Ratschläge zusammenfassen, erhalten wir etwas Ähnliches wie dies:

function ensureExists(path, mask, cb) {
    if (typeof mask == 'function') { // Erlauben Sie, dass der `mask` Parameter optional ist
        cb = mask;
        mask = 0o744;
    }
    fs.mkdir(path, mask, function(err) {
        if (err) {
            if (err.code == 'EEXIST') cb(null); // Ignorieren Sie den Fehler, wenn der Ordner bereits existiert
            else cb(err); // Etwas anderes ist schiefgegangen
        } else cb(null); // Ordner erfolgreich erstellt
    });
}

Und wir können es so verwenden:

ensureExists(__dirname + '/upload', 0o744, function(err) {
    if (err) // Fehler bei der Ordnererstellung behandeln
    else // Alles in Ordnung
});

Natürlich berücksichtigt dies nicht Randfälle wie

  • Was passiert, wenn der Ordner gelöscht wird, während Ihr Programm läuft? (vorausgesetzt, Sie überprüfen nur einmal, ob er beim Start vorhanden ist)
  • Was passiert, wenn der Ordner bereits existiert, aber die falschen Berechtigungen hat?

105voto

Modular Punkte 4694

Die Methode mkdir hat die Fähigkeit, alle Verzeichnisse in einem Pfad rekursiv zu erstellen, die nicht vorhanden sind, und diejenigen zu ignorieren, die es tun.

Aus der Node.js v10/11 Dokumentation:

// Erstellt /tmp/a/apple, unabhängig davon, ob `/tmp` und /tmp/a existieren.
fs.mkdir('/tmp/a/apple', { recursive: true }, (err) => {
    if (err) throw err;
});

HINWEIS: Du musst zuerst das eingebaute Modul fs importieren.

Hier ist nun ein etwas robusteres Beispiel, das native ECMAScript Module nutzt (mit aktivierter Flagge und der .mjs-Erweiterung), Nicht-Root-Pfade behandelt und vollständige Pfadnamen berücksichtigt:

import fs from 'fs';
import path from 'path';

function createDirectories(pathname) {
   const __dirname = path.resolve();
   pathname = pathname.replace(/^\.*\/|\/?[^\/]+\.[a-z]+|\/$/g, ''); // Entferne führende Verzeichnis-Marker und Entferne Endung /Dateiname-Erweiterung
   fs.mkdir(path.resolve(__dirname, pathname), { recursive: true }, e => {
       if (e) {
           console.error(e);
       } else {
           console.log('Erfolg');
       }
    });
}

Du kannst es wie folgt verwenden createDirectories('/components/widget/widget.js');.

Und natürlich würdest du wahrscheinlich auch etwas ausgefeilteres verwenden wollen, indem du Versprechen mit async/await verwendest, um die Dateierstellung in einer verständlicheren, synchron aussehenden Weise zu nutzen, wenn die Verzeichnisse erstellt werden; aber das geht über den Rahmen der Frage hinaus.

50voto

galki Punkte 7064

Mit dem fs-extra Paket können Sie dies mit einer einzigen Zeile tun:

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

const dir = '/tmp/this/path/does/not/exist';
fs.ensureDirSync(dir);

45voto

Toni Gamez Punkte 6541

Ich habe ein npm-Modul gefunden, das hier wie ein Zauber funktioniert.

Es führt einfach ein rekursives mkdir aus, wenn nötig, ähnlich wie "mkdir -p".

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X