Wie erstelle ich ein Verzeichnis, wenn es mit Node.js nicht existiert?


Antworten:


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

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

28
Wenn Sie diesen Vorgang beim Booten oder Initialisieren der App ausführen, ist es in Ordnung, die Ausführung zu blockieren, da Sie dasselbe tun würden, wenn Sie es asynchron ausführen würden. Wenn Sie ein Verzeichnis als wiederkehrenden Vorgang erstellen, führt dies zu einer schlechten Vorgehensweise, verursacht jedoch wahrscheinlich keine Leistungsprobleme, ist jedoch ein schlechter Habbit. Nur zum Booten Ihrer App oder für andere einmalige Vorgänge verwenden.
tsturzl

20
existiertSync () ist nicht veraltet, existiert () ist jedoch - nodejs.org/api/fs.html#fs_fs_existssync_path
Ian Chadwick

Die Verwendung von * SyncMethoden ist normalerweise ein Nein-Nein: Ich möchte die Ereignisschleife nicht blockieren
Max Heiber

14
Die Verwendung von Synchronisierungsmethoden ist für lokale Skripte und dergleichen in Ordnung, offensichtlich keine gute Idee für einen Server.
Pier

Wenn dieser Block von setTimeout umgeben ist, ist er asynchron .....................
Bryan Grace

185

Nein, aus mehreren Gründen.

  1. Das pathModul hat keine exists/ existsSync-Methode. Es ist im fsModul. (Vielleicht haben Sie gerade einen Tippfehler in Ihrer Frage gemacht?)

  2. Die Dokumente raten ausdrücklich von der Verwendung ab exists.

    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 die Überprüfung, ob eine Datei vor dem Öffnen vorhanden ist, ist ein Anti-Pattern, das Sie für Rennbedingungen anfällig macht: Ein anderer Prozess kann die Datei zwischen den Aufrufen von fs.exists()und entfernen fs.open(). Öffnen Sie einfach die Datei und behandeln Sie den Fehler, wenn er nicht vorhanden ist.

    Da es sich eher um ein Verzeichnis als um eine Datei handelt, bedeutet dieser Rat, dass Sie nur bedingungslos anrufen mkdirund ignorieren sollten EEXIST.

  3. Im Allgemeinen sollten Sie die * Sync-Methoden vermeiden . Sie blockieren, was bedeutet, dass absolut nichts anderes in Ihrem Programm passieren kann, während Sie auf die Festplatte gehen. Dies ist eine sehr teure Operation, und die dafür benötigte Zeit unterbricht die Kernannahme der Ereignisschleife des Knotens.

    Die * Sync-Methoden eignen sich normalerweise gut für schnelle Einzelskripte (diejenigen, die eine Sache tun und dann beenden), sollten jedoch fast nie verwendet werden, wenn Sie einen Server schreiben: Ihr Server kann während der gesamten Dauer nicht auf jemanden antworten der E / A-Anforderungen. Wenn für mehrere Clientanforderungen E / A-Vorgänge erforderlich sind, kommt Ihr Server sehr schnell zum Stillstand.


    Das einzige Mal, dass ich die Verwendung von * Sync-Methoden in einer Serveranwendung in Betracht ziehen würde, ist eine Operation , die beim Start einmal (und nur einmal) ausgeführt wird. Zum Beispiel wird require tatsächlichreadFileSync zum Laden von Modulen verwendet.

    Selbst dann müssen Sie immer noch vorsichtig sein, da viele synchrone E / A die Startzeit Ihres Servers unnötig verlangsamen können.


    Stattdessen sollten Sie die asynchronen E / A-Methoden verwenden.

Wenn wir also diese Ratschläge zusammenstellen, erhalten wir ungefähr Folgendes:

function ensureExists(path, mask, cb) {
    if (typeof mask == 'function') { // allow the `mask` parameter to be optional
        cb = mask;
        mask = 0777;
    }
    fs.mkdir(path, mask, function(err) {
        if (err) {
            if (err.code == 'EEXIST') cb(null); // ignore the error if the folder already exists
            else cb(err); // something else went wrong
        } else cb(null); // successfully created folder
    });
}

Und wir können es so verwenden:

ensureExists(__dirname + '/upload', 0744, function(err) {
    if (err) // handle folder creation error
    else // we're all good
});

Dies berücksichtigt natürlich keine Randfälle wie

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

1
Gibt es eine Möglichkeit, SyntaxError zu vermeiden: Oktal-Literale sind im strengen Modus nicht zulässig?
Whisher

8
Schreiben Sie es als Dezimalzahl. 0744 == 484.
Josh3736

3
Eine Alternative besteht darin, ein Modul zu verwenden, das fs erweitert, um diese Funktionalität zu haben, wie z. B. github.com/jprichardson/node-fs-extra
Bret

Ist diese "Masken" -Flagge im Jahr 2019 noch relevant? Was war der Zweck davon?
Oldboy

Dies ist der Unix-Dateimodus - die Lese- / Schreibberechtigungen des Verzeichnisses.
Josh3736


31

Die mkdirMethode kann rekursiv Verzeichnisse in einem Pfad erstellen , die nicht vorhanden sind, und diejenigen ignorieren, die dies tun.

Aus den Node v10 / 11-Dokumenten :

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

HINWEIS: Sie müssen zuerst das integrierte fsModul importieren .

Hier ist ein etwas robusteres Beispiel, das native ES-Module (mit aktiviertem Flag und Erweiterung .mjs) nutzt, Nicht-Root-Pfade verarbeitet und vollständige Pfadnamen berücksichtigt:

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

createDirectories(pathname) {
   const __dirname = path.resolve();
   pathname = pathname.replace(/^\.*\/|\/?[^\/]+\.[a-z]+|\/$/g, ''); // Remove leading directory markers, and remove ending /file-name.extension
   fs.mkdir(path.resolve(__dirname, pathname), { recursive: true }, e => {
       if (e) {
           console.error(e);
       } else {
           console.log('Success');
       }
    });
}

Sie können es wie verwenden createDirectories('/components/widget/widget.js');.

Und natürlich möchten Sie wahrscheinlich mehr Lust bekommen, indem Sie Versprechen mit async / await verwenden, um die Dateierstellung beim Erstellen der Verzeichnisse besser lesbar und synchron zu gestalten. Aber das geht über den Rahmen der Frage hinaus.


1
Warum const __dirname = path.resolve (); und nicht den eingebauten __dirname verwenden?
TamusJRoyce

29

Nur für den Fall, dass sich jemand für die einzeilige Version interessiert. :) :)

//or in typescript: import * as fs from 'fs';
const fs = require('fs');
!fs.existsSync(dir) && fs.mkdirSync(dir);

20

Sie können mkdirden Fehler einfach verwenden und abfangen, wenn der Ordner vorhanden ist.
Dies ist asynchron (also Best Practice) und sicher.

fs.mkdir('/path', err => { 
    if (err && err.code != 'EEXIST') throw 'up'
    .. safely do your stuff here  
    })

(Fügen Sie dem Modus optional ein zweites Argument hinzu.)


Andere Gedanken:

  1. Sie können dann verwenden oder warten, indem Sie native promisify verwenden .

    const util = require('util'), fs = require('fs');
    const mkdir = util.promisify(fs.mkdir);
    var myFunc = () => { ..do something.. } 
    
    mkdir('/path')
        .then(myFunc)
        .catch(err => { if (err.code != 'EEXIST') throw err; myFunc() })
  2. Sie können Ihre eigene Versprechungsmethode erstellen, etwa (ungetestet):

    let mkdirAsync = (path, mode) => new Promise(
       (resolve, reject) => mkdir (path, mode, 
          err => (err && err.code !== 'EEXIST') ? reject(err) : resolve()
          )
       )
  3. Für die synchrone Überprüfung können Sie Folgendes verwenden:

    fs.existsSync(path) || fs.mkdirSync(path)
  4. Oder Sie können eine Bibliothek verwenden, die zwei beliebtesten Wesen


1
Für den vielversprechenden Ansatz Nr. 1 könnten Sie den Fang neu arrangieren. mkdir('/path').catch(err => { if (err.code != 'EEXIST') throw err;}).then(myFunc);
Was wäre cool

Und verwenden Sie !==anstelle von!=
Quentin Roy

18

Mit dem fs-extra- Paket können Sie dies mit einem Einzeiler tun :

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

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

Eine so unterschätzte Antwort! fs-extra hat Bacame ein Muss für mich. Ich denke, es ist eine Abkürzung, mehr als 10 Zeilen juste zu schreiben, um zu überprüfen, ob ein Ordner existiert ...
538ROMEO

10

Die beste Lösung wäre die Verwendung des npm-Moduls namens node-fs-extra . Es hat eine Methode namens, mkdirdie das von Ihnen erwähnte Verzeichnis erstellt. Wenn Sie einen langen Verzeichnispfad angeben, werden die übergeordneten Ordner automatisch erstellt. Das Modul ist ein Super-Set von npm-Modulen fs, sodass Sie alle Funktionen fsauch dann verwenden können, wenn Sie dieses Modul hinzufügen.


6
var dir = 'path/to/dir';
try {
  fs.mkdirSync(dir);
} catch(e) {
  if (e.code != 'EEXIST') throw e;
}

4
Für Node.js v7.4.0 wird in der Dokumentation angegeben , dass dies fs.exists()veraltet ist, jedoch fs.existsSync()nicht. Könnten Sie einen Link zu einer Ressource hinzufügen, die besagt, dass sie fs.existsSync()abgeschrieben ist?
Francis

1
Nur-Code-Antworten sind für Benutzer, die in Zukunft auf diese Frage kommen, nicht sehr hilfreich. Bitte bearbeiten Sie Ihre Antwort, um zu erklären, warum Ihr Code das ursprüngliche Problem löst
yivi


1
Vielen Dank! Es scheint, dass die Funktion in Version 0.12 existierte, in Version 4 und 5 veraltet und in Version 6 und 7 wiederhergestellt wurde ... Eine Art Zombi-Funktion ...
Francis

1
Ja, anscheinend ist es jetzt NICHT veraltet ab Apr 2018: nodejs.org/api/fs.html#fs_fs_existssync_path
LeOn - Han Li

5
    var filessystem = require('fs');
    var dir = './path/subpath/';

    if (!filessystem.existsSync(dir)){
        filessystem.mkdirSync(dir);
    }else
    {
        console.log("Directory already exist");
    }

Das kann dir helfen :)


5

ENOENT: Keine solche Datei oder kein solches Verzeichnis

Lösung

const fs = require('fs')  // in javascript
import * as fs from "fs"  // in typescript
import fs from "fs"       // in typescript

// it will create the directory if it does not exist.
!fs.existsSync(`./assets/`) && fs.mkdirSync(`./assets/`, { recursive: true })

1
das funktioniert, danke
Aljohn Yamaro

3

Ich möchte einen Typescript Promise Refactor der Antwort von josh3736 hinzufügen .

Es macht das Gleiche und hat die gleichen Randfälle, es verwendet nur Promises, Typoskript-Typedefs und arbeitet mit "use strict".

// https://en.wikipedia.org/wiki/File_system_permissions#Numeric_notation
const allRWEPermissions = parseInt("0777", 8);

function ensureFilePathExists(path: string, mask: number = allRWEPermissions): Promise<void> {
    return new Promise<void>(
        function(resolve: (value?: void | PromiseLike<void>) => void,
            reject: (reason?: any) => void): void{
            mkdir(path, mask, function(err: NodeJS.ErrnoException): void {
                if (err) {
                    if (err.code === "EEXIST") {
                        resolve(null); // ignore the error if the folder already exists
                    } else {
                        reject(err); // something else went wrong
                    }
                } else {
                    resolve(null); // successfully created folder
                }
            });
    });
}

3

Mit Knoten 10 + ES6:

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

(async () => {
  const dir = path.join(__dirname, 'upload');

  try {
    await fs.promises.mkdir(dir);
  } catch (error) {
    if (error.code === 'EEXIST') {
      // Something already exists, but is it a file or directory?
      const lstat = await fs.promises.lstat(dir);

      if (!lstat.isDirectory()) {
        throw error;
      }
    } else {
      throw error;
    }
  }
})();

2

Mit dem Befehl fs.stat des Dateisystemknotens können Sie überprüfen, ob dir vorhanden ist, und mit fs.mkdir ein Verzeichnis mit Rückruf erstellen oder mit fs.mkdirSync ein Verzeichnis ohne Rückruf erstellen, wie in diesem Beispiel:

//first require fs
const fs = require('fs');

// Create directory if not exist (function)
const createDir = (path) => {
    // check if dir exist
    fs.stat(path, (err, stats) => {
        if (stats.isDirectory()) {
            // do nothing
        } else {
            // if the given path is not a directory, create a directory
            fs.mkdirSync(path);
        }
    });
};

1

Hier ist eine kleine Funktion zum rekursiven Erstellen von Verzeichnissen:

const createDir = (dir) => {
  // This will create a dir given a path such as './folder/subfolder' 
  const splitPath = dir.split('/');
  splitPath.reduce((path, subPath) => {
    let currentPath;
    if(subPath != '.'){
      currentPath = path + '/' + subPath;
      if (!fs.existsSync(currentPath)){
        fs.mkdirSync(currentPath);
      }
    }
    else{
      currentPath = subPath;
    }
    return currentPath
  }, '')
}

0

Verwenden von async / await:

const mkdirP = async (directory) => {
  try {
    return await fs.mkdirAsync(directory);
  } catch (error) {
    if (error.code != 'EEXIST') {
      throw e;
    }
  }
};

Sie müssen versprechen fs:

import nodeFs from 'fs';
import bluebird from 'bluebird';

const fs = bluebird.promisifyAll(nodeFs);
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.