Node.js utwórz folder lub użyj istniejącego

186

Przeczytałem już dokumentację Node.js i, chyba że coś przeoczyłem, nie mówi w szczególności, jakie parametry zawierają niektóre operacje fs.mkdir(). Jak widać w dokumentacji, to niewiele.

Obecnie mam ten kod, który próbuje utworzyć folder lub użyć istniejącego zamiast tego:

fs.mkdir(path,function(e){
    if(!e || (e && e.code === 'EEXIST')){
        //do something with contents
    } else {
        //debug
        console.log(e);
    }
});

Ale zastanawiam się, czy to właściwy sposób, aby to zrobić? Czy sprawdzenie kodu EEXISTto właściwy sposób, aby wiedzieć, że folder już istnieje? Wiem, że mogę to zrobić fs.stat()przed utworzeniem katalogu, ale byłoby to już dwa trafienia do systemu plików.

Po drugie, czy istnieje pełna lub przynajmniej bardziej szczegółowa dokumentacja Node.js, która zawiera szczegółowe informacje o tym, jakie obiekty błędów zawierają, jakie parametry oznaczają itp.

Joseph
źródło
31
Mały nitpick, ale pozbądź się e &&. Jeśli !ezawiedzie, to wiesz, że eto prawda.
I Hate Lazy

Odpowiedzi:

236

Dobrym sposobem na to jest użycie modułu mkdirp .

$ npm install mkdirp

Użyj go, aby uruchomić funkcję wymagającą katalogu. Oddzwanianie jest wywoływane po utworzeniu ścieżki lub jeśli ścieżka już istnieje. Błąd errjest ustawiany, jeśli mkdirp nie utworzył ścieżki do katalogu.

var mkdirp = require('mkdirp');
mkdirp('/tmp/some/path/foo', function(err) { 

    // path exists unless there was an error

});
Teemu Ikonen
źródło
3
Wydaje mi się, że poprawną odpowiedzią (czytaj „bez dodania zależności”) byłaby odpowiedź niższa, autorstwa @Raugaral, przy użyciu fs.exists(Sync).
Ricardo Pedroni,
@meawoppl, jest to „makedirectory” p. „P” jest nieznane.
Andrew
4
@RicardoPedroni Prawidłowym sposobem jest użycie modułu. Moduły zwykle z całego serca próbują rozwiązać jeden problem i często są utrzymywane. Możesz je łatwo zaktualizować za pomocą npm. Powinieneś także unikać używania fs.exists [Sync], ponieważ jego użycie oznacza warunki wyścigowe.
1j01
16
@ 1j01 Nie sądzę, że poprawnym sposobem jest użycie modułu, jeśli platforma natywnie obsługuje tę operację. To droga do chaosu. Muszę się zgodzić, że są lepsze odpowiedzi z technicznego punktu widzenia.
c ..
2
@ 1j01 Ponadto użycie operacji synchronizacji implikuje warunki wyścigu, ponieważ ich użycie stanowi dla nich rozwiązanie.
c ..
193

Edycja: Ponieważ ta odpowiedź jest bardzo popularna, zaktualizowałem ją, aby odzwierciedlała aktualne praktyki.

Węzeł> = 10

Nowa { recursive: true }opcja Node's fspozwala teraz na to natywnie. Ta opcja naśladuje zachowanie systemu UNIX mkdir -p. Rekurencyjnie upewni się, że każda część ścieżki istnieje i nie wyśle ​​błędu, jeśli którakolwiek z nich się pojawi.

(Uwaga: wciąż może generować błędy, takie jak EPERMlub EACCESS, więc lepiej zawiń go, try {} catch (e) {}jeśli twoja implementacja jest na to podatna).

Wersja synchroniczna.

fs.mkdirSync(dirpath, { recursive: true })

Wersja asynchroniczna

await fs.promises.mkdir(dirpath, { recursive: true })

Starsze wersje węzłów

Za pomocą a try {} catch (err) {}możesz to osiągnąć bardzo wdzięcznie, nie spotykając warunków wyścigu.

Aby uniknąć martwego czasu między sprawdzeniem istnienia a utworzeniem katalogu, po prostu staramy się go utworzyć od razu i zignorować błąd, jeśli tak jest EEXIST(katalog już istnieje).

Jeśli błąd nie jest EEXIST, powinniśmy jednak rzucić błąd, ponieważ możemy mieć do czynienia z czymś takim jak EPERMlubEACCES

function ensureDirSync (dirpath) {
  try {
    return fs.mkdirSync(dirpath)
  } catch (err) {
    if (err.code !== 'EEXIST') throw err
  }
}

Dla mkdir -p-Jak rekurencyjnego zachowań, np ./a/b/c, trzeba by nazwać na każdej części dirpath, np ./a, ./a/b,.a/b/c

Christophe Marois
źródło
var fs = Npm.require ('fs'); var dir = process.env.PWD + '/ files / users /' + this.userId + '/'; spróbuj {fs.mkdirSync (reż); } catch (e) {if (e.code! = 'EEXIST') throw e; }
Aaron
Wypróbowałem twój kod, stwórz skrypt js, który wykorzystuje tworzenie katalogu w następujący sposób: mkdirpSync (ścieżka.join (__ nazwa_katalogu, „pierwszy”, „drugi”, „trzeci”, „ololol”, „działa”)); Ale dostał ten błąd: $ node 1.js fs.js: 747 return binding.mkdir (pathModule._makeLong (ścieżka), ^ Błąd: EPERM, operacja niedozwolona „C: \” w przypadku błędu (natywny) w Object.fs. mkdirSync (fs.js: 747: 18) w mkdirpSync (C: \ Users \ MAXIM \ Desktop \ test \ 1.js: 15: 8) w Object. <anonimowy> (C: \ Users \ MAXIM \ Desktop \ test \ 1.js: 19: 1) ... Czy możesz zasugerować, co może być nie tak? Oczywiście używany w
systemie
Wydaje się, że EPERM to kwestia pozwolenia, więc skrypt i tak nie złamałby egzekucji
Christophe Marois
Myślę, że byłoby lepiej: var mkdirpSync = function (dirpath) {var parts = dirpath.split (path.sep); for (var i = 1; i <= parts.length; i ++) {try {fs.mkdirSync (path.join.apply (null, parts.slice (0, i))); } catch (error) {if (error.code! = 'EEXIST') {error throw; }}}}
manish
1
ostrzeżenie: nie działa, jeśli twoja ścieżka zaczyna się od /
acemtp
62

Jeśli chcesz szybko i zabrudzić jedną wkładkę, użyj tego:

fs.existsSync("directory") || fs.mkdirSync("directory");
marekventur
źródło
1
fs.existsjest przestarzałe: nodejs.org/api/fs.html#fs_fs_exists_path_callback
adius
7
fs.existsSync (...) nie jest jednak przestarzałe, więc ta odpowiedź wydaje się odpowiednia.
Dan Haywood,
Heads-up! Nie będzie działać dla „dir / foo / bar”, tzn. Nie ma opcji flagi mkdir -p
Karl Pokus
Ma to również warunek wyścigu
Evert
26

Dokumenty node.js, aby w fs.mkdirzasadzie odroczyć stronę podręcznika systemu Linux dla mkdir(2). Oznacza to, że EEXISTbędzie to wskazane również, jeśli ścieżka istnieje, ale nie jest katalogiem, który tworzy niezręczną skrzynkę narożną, jeśli wybierzesz tę trasę.

Lepiej jest zadzwonić, fs.statco powie ci, czy ścieżka istnieje i czy jest to katalog w jednym wywołaniu. W przypadku (zakładam, że) normalnego przypadku, w którym katalog już istnieje, jest to tylko jeden trafiony system plików.

Te fsmetody modułowe są cienkimi opakowaniami wokół natywnych interfejsów API języka C, dlatego należy sprawdzić strony podręcznika, do których odwołuje się dokumentacja node.js, w celu uzyskania szczegółowych informacji.

JohnnyHK
źródło
19
Wywołanie statwcześniej mkdirmoże mieć wpływ na warunki wyścigowe - pamiętaj o tym.
Roger Lipscombe,
24

Możesz użyć tego:

if(!fs.existsSync("directory")){
    fs.mkdirSync("directory", 0766, function(err){
        if(err){
            console.log(err);
            // echo the result back
            response.send("ERROR! Can't make the directory! \n");
        }
    });
}
Raugaral
źródło
1
-1. Nie wierzę, że to działa, statSyncspowoduje błąd, jeśli jednostka w ogóle nie istnieje, powodując awarię kodu. Musisz owinąć to w try/catchblok.
Chris Foster
2
Przepraszam nie mam racji. zmień „statSync” na „existSync”
Raugaral
5
Według nodejs.org/api/fs.html#fs_fs_mkdirsync_path_mode wariant synchronizacji mkdir nie przyjmuje oddzwonienia
Danwellman
1
Według nodejs.org/api/fs.html#fs_fs_existssync_path , fs.existsSync()i fs.exists()będą przestarzałe.
pau.moreno
7

Proponuję rozwiązanie bez modułów (akumulacja modułów nigdy nie jest zalecana ze względu na łatwość konserwacji, szczególnie w przypadku małych funkcji, które można zapisać w kilku wierszach ...):

OSTATNIA AKTUALIZACJA :

W wersji 10.12.0 opcje rekurencyjne implementacji NodeJS:

// Create recursive folder
fs.mkdir('my/new/folder/create', { recursive: true }, (err) => { if (err) throw err; });

AKTUALIZACJA :

// Get modules node
const fs   = require('fs');
const path = require('path');

// Create 
function mkdirpath(dirPath)
{
    if(!fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK))
    {
        try
        {
            fs.mkdirSync(dirPath);
        }
        catch(e)
        {
            mkdirpath(path.dirname(dirPath));
            mkdirpath(dirPath);
        }
    }
}

// Create folder path
mkdirpath('my/new/folder/create');
Liberateur
źródło
fs.exists()jest przestarzałe w węźle v9. użyj fs.access()zamiast tego. (zwraca, undefinedjeśli plik istnieje; w przeciwnym razie zgłasza błąd ENOENT)
chharvey
Bez pakietu npm działa. To cenny kod. Dzięki
Karthik Sridharan
Ten jest znacznie lepszy do tworzenia folderu pod istniejącą długą ścieżką;) Dzięki, stary.
Tsung Goh
1
Co fs.mkdirSync('my/new/folder/create', {recursive: true})?
saitho
Dzięki ! Aktualizuję swój post, aby pomagać innym. Węzeł 10.12.0 był zbyt nowy.
Liberateur
4

Możesz także użyć programu fs-extra , który zapewnia często używane operacje na plikach.

Przykładowy kod:

var fs = require('fs-extra')

fs.mkdirs('/tmp/some/long/path/that/prob/doesnt/exist', function (err) {
  if (err) return console.error(err)
  console.log("success!")
})

fs.mkdirsSync('/tmp/another/path')

dokumenty tutaj: https://github.com/jprichardson/node-fs-extra#mkdirsdir-callback

Geng Jiawen
źródło
4

Oto kod ES6, którego używam do utworzenia katalogu (jeśli nie istnieje):

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

function createDirectory(directoryPath) {
  const directory = path.normalize(directoryPath);

  return new Promise((resolve, reject) => {
    fs.stat(directory, (error) => {
      if (error) {
        if (error.code === 'ENOENT') {
          fs.mkdir(directory, (error) => {
            if (error) {
              reject(error);
            } else {
              resolve(directory);
            }
          });
        } else {
          reject(error);
        }
      } else {
        resolve(directory);
      }
    });
  });
}

const directoryPath = `${__dirname}/test`;

createDirectory(directoryPath).then((path) => {
  console.log(`Successfully created directory: '${path}'`);
}).catch((error) => {
  console.log(`Problem creating directory: ${error.message}`)
});

Uwaga:

  • Na początku createDirectoryfunkcji normalizuję ścieżkę, aby zagwarantować, że typ separatora ścieżek systemu operacyjnego będzie używany konsekwentnie (np. Zmieni się to C:\directory/testwC:\directory\test (w systemie Windows)
  • fs.existsjest przestarzałe , dlatego używam fs.statdo sprawdzenia, czy katalog już istnieje
  • Jeśli katalog nie istnieje, kod błędu to ENOENT( E rror NO ENT ry)
  • Sam katalog zostanie utworzony za pomocą fs.mkdir
  • Wolę funkcję asynchroniczną fs.mkdirniż jej blokujący odpowiednik, fs.mkdirSynca ze względu na zawijanie Promisezagwarantuje, że ścieżka katalogu zostanie zwrócona dopiero po pomyślnym utworzeniu katalogu
Benny Neugebauer
źródło
Dziękujemy za czyste rozwiązanie, które nie wymaga niepotrzebnych modułów. To działało idealnie dla mnie. Chciałbym, żeby było więcej takich odpowiedzi!
Ken Lyon,
3

Moim zdaniem lepiej nie liczyć trafień w system plików podczas kodowania w JavaScript. Jednak (1) stat& mkdiri (2) mkdiri sprawdzić (lub odrzutów) kod błędu, obie strony mają prawo sposobów na to, co chcesz.

Chul-Woong Yang
źródło
-1, nie rozumiem, w jaki sposób sprawdzanie lub odrzucanie może być dobrym sposobem na zrobienie tego. To prawie nie ma odpowiedzi.
Matt Ball,
Jest to dobry sposób na uruchomienie katalogu mkdir lub użycie istniejącego. Nie rozumiem, dlaczego nie widzisz. Sprawdzanie kodu błędu jest grzeczne, a odrzucanie kodu błędu jest po prostu dobre. nie zgadzasz się?
Chul-Woong Yang,
1
Być może jest to problem z barierą językową, ale czytam to jako brak odpowiedzi na pytanie zadane przez PO.
Matt Ball,
Rozumiem o co ci chodzi. Uważam jednak, że istnieje wiele sposobów na poprawne działanie. Dzięki.
Chul-Woong Yang,
2

utwórz katalog nazw dynamicznych dla każdego użytkownika ... użyj tego kodu

***suppose email contain user mail address***

var filessystem = require('fs');
var dir = './public/uploads/'+email;

if (!filessystem.existsSync(dir)){
  filessystem.mkdirSync(dir);

}else
{
    console.log("Directory already exist");
}
Adii
źródło
1

Możesz to wszystko zrobić za pomocą modułu systemu plików.

const
  fs = require('fs'),
  dirPath = `path/to/dir`

// Check if directory exists.
fs.access(dirPath, fs.constants.F_OK, (err)=>{
  if (err){
    // Create directory if directory does not exist.
    fs.mkdir(dirPath, {recursive:true}, (err)=>{
      if (err) console.log(`Error creating directory: ${err}`)
      else console.log('Directory created successfully.')
    })
  }
  // Directory now exists.
})

Naprawdę nie musisz nawet sprawdzać, czy katalog istnieje. Poniższy kod gwarantuje również, że katalog już istnieje lub został utworzony.

const
  fs = require('fs'),
  dirPath = `path/to/dir`

// Create directory if directory does not exist.
fs.mkdir(dirPath, {recursive:true}, (err)=>{
  if (err) console.log(`Error creating directory: ${err}`)
  // Directory now exists.
})
stary chłopiec
źródło
0

Odpowiedź Raugarala, ale z funkcją -p. Brzydkie, ale działa:

function mkdirp(dir) {
    let dirs = dir.split(/\\/).filter(asdf => !asdf.match(/^\s*$/))
    let fullpath = ''

    // Production directory will begin \\, test is on my local drive.
    if (dirs[0].match(/C:/i)) {
        fullpath = dirs[0] + '\\'
    }
    else {
        fullpath = '\\\\' + dirs[0] + '\\'
    }

    // Start from root directory + 1, build out one level at a time.
    dirs.slice(1).map(asdf => {
        fullpath += asdf + '\\'
        if (!fs.existsSync(fullpath)) {
            fs.mkdirSync(fullpath)
        }
    })
}//mkdirp
użytkownik8675309
źródło
0

Tak jak nowszą alternatywą dla odpowiedzi Teemu Ikonen , która jest bardzo prosta i czytelna, jest użycie ensureDirmetody fs-extrapakietu.

Może być stosowany nie tylko jako rażący zamiennik wbudowanego fsmodułu, ale ma także wiele innych funkcji oprócz funkcjifs pakietu.

ensureDirSposób, jak sama nazwa wskazuje, zapewnia, że katalog istnieje. Jeśli struktura katalogów nie istnieje, zostanie utworzona. Lubićmkdir -p . Nie tylko folder końcowy, zamiast tego tworzona jest cała ścieżka, jeśli jeszcze nie istnieje.

powyższy jest jego asyncwersją. Ma również metodę synchroniczną, aby wykonać to w formie ensureDirSyncmetody.

Rai
źródło
0

Powyższa odpowiedź @ Liberateur nie zadziałała dla mnie (Node v8.10.0). Niewielka modyfikacja pomogła, ale nie jestem pewien, czy jest to właściwy sposób. Proszę zasugeruj.

// Get modules node
const fs   = require('fs');
const path = require('path');

// Create
function mkdirpath(dirPath)
{
    try {
        fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK);
    }
    catch(err) {
        try
        {
            fs.mkdirSync(dirPath);
        }
        catch(e)
        {
            mkdirpath(path.dirname(dirPath));
            mkdirpath(dirPath);
        }
    }
}

// Create folder path
mkdirpath('my/new/folder/create');
nik
źródło