web-dev-qa-db-de.com

Wie erstelle ich einen vollständigen Pfad mit fs.mkdirSync des Knotens?

Ich versuche, einen vollständigen Pfad zu erstellen, falls er nicht existiert.

Der Code sieht so aus:

var fs = require('fs');
if (!fs.existsSync(newDest)) fs.mkdirSync(newDest); 

Dieser Code funktioniert gut, solange es nur ein Unterverzeichnis gibt (ein newDest wie 'dir1'). Wenn jedoch ein Verzeichnispfad ('dir1/dir2') vorhanden ist, schlägt er mit Fehler fehl: ENOENT, keine solche Datei oder Verzeichnis

Ich möchte in der Lage sein, den vollständigen Pfad mit so wenig Codezeilen wie nötig zu erstellen.

Ich habe gelesen, dass es eine rekursive Option für fs gibt und es so ausprobiert hat

var fs = require('fs');
if (!fs.existsSync(newDest)) fs.mkdirSync(newDest,'0777', true);

Ich denke, es sollte so einfach sein, ein Verzeichnis rekursiv zu erstellen, das nicht existiert. Fehlt mir etwas oder muss ich den Pfad analysieren und jedes Verzeichnis überprüfen und erstellen, wenn es noch nicht existiert?

Ich bin ziemlich neu in Node. Vielleicht verwende ich eine alte Version von FS?

98

Eine Option ist die Verwendung von shelljs module

npm install shelljs

var Shell = require('shelljs');
Shell.mkdir('-p', fullPath);

Von dieser Seite:

Verfügbare Optionen:

p: vollständiger Pfad (erstellt ggf. Zwischenverzeichnisse)

Wie andere bereits bemerkt haben, gibt es noch andere fokussierte Module. Aber außerhalb von mkdirp gibt es jede Menge anderer nützlicher Shell-Operationen (wie which, grep etc ...) und es funktioniert unter Windows und * nix

45
bryanmac

Bearbeiten

NodeJS Version 10 hat eine native Unterstützung für mkdir und mkdirSync hinzugefügt, um ein Verzeichnis rekursiv mit der Option recursive: true wie folgt zu erstellen:

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

Und wenn Sie fs Promises API bevorzugen, können Sie schreiben

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

Ursprüngliche Antwort

Erstellen Sie rekursiv Verzeichnisse, wenn sie nicht existieren! (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);
}

Verwendungszweck

// 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 behandelt plattformspezifische Fehler wie EISDIR für Mac und EPERM und EACCES für Windows. Vielen Dank an alle Berichterstattungen von @PediT., @JohnQ, @ deed02392, @robyoder und @Almenon.
  • Diese Lösung behandelt die Pfade relative und absolute. Vielen Dank an @John Kommentar.
  • Bei relativen Pfaden werden Zielverzeichnisse im aktuellen Arbeitsverzeichnis angelegt (aufgelöst). Um sie relativ zum aktuellen Skriptverzeichnis aufzulösen, übergeben Sie {isRelativeToScript: true}.
  • Verwenden Sie path.sep und path.resolve() , nicht nur /-Verkettung, um plattformübergreifende Probleme zu vermeiden.
  • Verwenden von fs.mkdirSync und Behandeln des Fehlers mit try/catch, wenn geworfen, um Racebedingungen zu behandeln: Ein anderer Prozess kann die Datei zwischen den Aufrufen zu fs.existsSync() und fs.mkdirSync() hinzufügen und eine Ausnahme verursachen .
    • Die andere Möglichkeit, dies zu erreichen, könnte sein, zu prüfen, ob eine Datei vorhanden ist, und dann erstellen, dh, if (!fs.existsSync(curDir) fs.mkdirSync(curDir);. Dies ist jedoch ein Anti-Pattern, das den Code anfällig für Rassenbedingungen macht. Dank @GershomMaes Kommentar zur Verzeichnisbestandsüberprüfung.
  • Benötigt Node v6 und neuer, um die Destrukturierung zu unterstützen. (Wenn Sie Probleme beim Implementieren dieser Lösung mit älteren Node-Versionen haben, schreiben Sie mir einfach einen Kommentar.)
153
Mouneer

Eine robustere Antwort ist die Verwendung von mkdirp .

var mkdirp = require('mkdirp');

mkdirp('/path/to/dir', function (err) {
    if (err) console.error(err)
    else console.log('dir created')
});

Dann schreiben Sie die Datei in den vollständigen Pfad mit:

fs.writeFile ('/path/to/dir/file.dat'....
69
cshotton

fs-extra fügt Dateisystemmethoden hinzu, die nicht im nativen fs-Modul enthalten sind. Es ist ein Rückgang des Ersatzes für fs.

fs-extra installieren

$ npm install --save fs-extra

const fs = require("fs-extra");
// Make sure the output directory is there.
fs.ensureDirSync(newDest);

Es gibt Synchronisations- und Asynchron-Optionen.

https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureDir.md

42
Deejers

Durch das Reduzieren können wir überprüfen, ob die einzelnen Pfade vorhanden sind, und sie ggf. erstellen. Auch auf diese Weise denke ich, ist es einfacher zu folgen. Dank @Arvin bearbeitet, sollten wir path.sep verwenden, um das richtige plattformspezifische Trennzeichen für Pfadsegmente zu erhalten.

const path = require('path');

// Path separators could change depending on the platform
const pathToCreate = 'path/to/dir'; 
pathToCreate
 .split(path.sep)
 .reduce((prevPath, folder) => {
   const currentPath = path.join(prevPath, folder, path.sep);
   if (!fs.existsSync(currentPath)){
     fs.mkdirSync(currentPath);
   }
   return currentPath;
 }, '');
29
josebui

Diese Funktion wurde zu node.js in Version 10.12.0 hinzugefügt. Sie können also einfach die Option {recursive: true} als zweites Argument an den fs.mkdir()-Aufruf ..__ übergeben. Siehe das Beispiel in den offiziellen docs .

Keine Notwendigkeit für externe Module oder eigene Implementierung.

25
Capaj

ich weiß, dass dies eine alte Frage ist, aber nodejs v10.12 unterstützt dies jetzt nativ mit der Option recursive, die auf true gesetzt ist. fs.mkdir

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

Sie können die nächste Funktion verwenden

const recursiveUpload = (Pfad: Zeichenfolge) => { const pfade = pfad.split ("/")

const fullPath = paths.reduce((accumulator, current) => {
  fs.mkdirSync(accumulator)
  return `${accumulator}/${current}`
  })

  fs.mkdirSync(fullPath)

  return fullPath
}

Was macht es also:

  1. Erstellen Sie die Variable paths, in der jeder Pfad einzeln als Element des Arrays gespeichert wird.
  2. Fügt "/" am Ende jedes Elements im Array ein.
  3. Macht für den Zyklus:
    1. Erstellt ein Verzeichnis aus der Verkettung von Arrayelementen, deren Indizes von 0 bis zur aktuellen Iteration reichen. Grundsätzlich ist es rekursiv.

Hoffentlich hilft das!

Im Knoten v10.12.0 können Sie übrigens die rekursive Pfaderstellung verwenden, indem Sie sie als zusätzliches Argument angeben. 

fs.mkdir('/tmp/a/Apple', { recursive: true }, (err) => { if (err) throw err; });

https://nodejs.org/api/fs.html#fs_fs_mkdirsync_path_options

2
hypeofpipe

Zu viele Antworten, aber hier ist eine Lösung ohne Rekursion, die funktioniert, indem der Pfad geteilt und dann von links nach rechts wieder aufgebaut wird

function mkdirRecursiveSync(path) {
    let paths = path.split(path.delimiter);
    let fullPath = '';
    paths.forEach((path) => {

        if (fullPath === '') {
            fullPath = path;
        } else {
            fullPath = fullPath + '/' + path;
        }

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

Für diejenigen, die sich mit der Windows-/Linux-Kompatibilität befassen, ersetzen Sie einfach den Schrägstrich durch einen doppelten Backslash '\' in beiden Fällen, aber bei TBH handelt es sich um den Knoten fs und nicht um die Windows-Befehlszeile. Ersteres ist ziemlich nachsichtig und der obige Code funktioniert einfach unter Windows und ist mehr eine plattformübergreifende Komplettlösung.

1
Hamiora

Beispiel für Windows (keine zusätzlichen Abhängigkeiten und Fehlerbehandlung)

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

let dir = "C:\\temp\\dir1\\dir2\\dir3";

function createDirRecursively(dir) {
    if (!fs.existsSync(dir)) {        
        createDirRecursively(path.join(dir, ".."));
        fs.mkdirSync(dir);
    }
}

createDirRecursively(dir); //creates dir1\dir2\dir3 in C:\temp
1
Andrey Imshenik

Mit NodeJS> = 10 können Sie fs.mkdirSync(path, { recursive: true })fs.mkdirSync verwenden.

1
William Penagos
const fs = require('fs');

try {
    fs.mkdirSync(path, { recursive: true });
} catch (error) {
    // this make script keep running, even when folder already exist
    console.log(error);
}
1
Choco Li

Basierend auf der Antwort von mouneer zero-dependencies, hier eine etwas Anfängerfreundlichere TypeScript-Variante, als Modul:

import * as fs from 'fs';
import * as path from 'path';

/**
* Recursively creates directories until `targetDir` is valid.
* @param targetDir target directory path to be created recursively.
* @param isRelative is the provided `targetDir` a relative path?
*/
export function mkdirRecursiveSync(targetDir: string, isRelative = false) {
    const sep = path.sep;
    const initDir = path.isAbsolute(targetDir) ? sep : '';
    const baseDir = isRelative ? __dirname : '.';

    targetDir.split(sep).reduce((prevDirPath, dirToCreate) => {
        const curDirPathToCreate = path.resolve(baseDir, prevDirPath, dirToCreate);
        try {
            fs.mkdirSync(curDirPathToCreate);
        } catch (err) {
            if (err.code !== 'EEXIST') {
                throw err;
            }
            // caught EEXIST error if curDirPathToCreate already existed (not a problem for us).
        }

        return curDirPathToCreate; // becomes prevDirPath on next call to reduce
    }, initDir);
}
0
brokenthorn

Sie können den Ordner einfach rekursiv überprüfen, ob der Pfad vorhanden ist oder nicht, und den Ordner erstellen, während Sie prüfen, ob sie nicht vorhanden sind. ( KEINE EXTERNE BIBLIOTHEK )

function checkAndCreateDestinationPath (fileDestination) {
    const dirPath = fileDestination.split('/');
    dirPath.forEach((element, index) => {
        if(!fs.existsSync(dirPath.slice(0, index + 1).join('/'))){
            fs.mkdirSync(dirPath.slice(0, index + 1).join('/')); 
        }
    });
}
0
Pulkit Aggarwal

Hier ist meine imperative Version von mkdirp für nodejs.

function mkdirSyncP(location) {
    let normalizedPath = path.normalize(location);
    let parsedPathObj = path.parse(normalizedPath);
    let curDir = parsedPathObj.root;
    let folders = parsedPathObj.dir.split(path.sep);
    folders.Push(parsedPathObj.base);
    for(let part of folders) {
        curDir = path.join(curDir, part);
        if (!fs.existsSync(curDir)) {
            fs.mkdirSync(curDir);
        }
    }
}
0
ubershmekel

Eine asynchrone Methode zum rekursiven Erstellen von Verzeichnissen:

import fs from 'fs'

const mkdirRecursive = function(path, callback) {
  let controlledPaths = []
  let paths = path.split(
    '/' // Put each path in an array
  ).filter(
    p => p != '.' // Skip root path indicator (.)
  ).reduce((memo, item) => {
    // Previous item prepended to each item so we preserve realpaths
    const prevItem = memo.length > 0 ? memo.join('/').replace(/\.\//g, '')+'/' : ''
    controlledPaths.Push('./'+prevItem+item)
    return [...memo, './'+prevItem+item]
  }, []).map(dir => {
    fs.mkdir(dir, err => {
      if (err && err.code != 'EEXIST') throw err
      // Delete created directory (or skipped) from controlledPath
      controlledPaths.splice(controlledPaths.indexOf(dir), 1)
      if (controlledPaths.length === 0) {
        return callback()
      }
    })
  })
}

// Usage
mkdirRecursive('./photos/recent', () => {
  console.log('Directories created succesfully!')
})
0
muratgozel

Wie wäre es mit diesem Ansatz:

if (!fs.existsSync(pathToFile)) {
            var dirName = "";
            var filePathSplit = pathToFile.split('/');
            for (var index = 0; index < filePathSplit.length; index++) {
                dirName += filePathSplit[index]+'/';
                if (!fs.existsSync(dirName))
                    fs.mkdirSync(dirName);
            }
        }

Dies funktioniert für den relativen Pfad. 

0

So sauber wie das :)

function makedir(fullpath) {
  let destination_split = fullpath.replace('/', '\\').split('\\')
  let path_builder = destination_split[0]
  $.each(destination_split, function (i, path_segment) {
    if (i < 1) return true
    path_builder += '\\' + path_segment
    if (!fs.existsSync(path_builder)) {
      fs.mkdirSync(path_builder)
    }
  })
}
0
Bob Vandevliet