Node.js crea una cartella o usa esistente


186

Ho già letto la documentazione di Node.js e, se non ho perso qualcosa, non dice cosa contengono i parametri in determinate operazioni, in particolare fs.mkdir(). Come puoi vedere nella documentazione, non è molto.

Attualmente, ho questo codice, che tenta di creare una cartella o utilizzare invece una esistente:

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

Ma mi chiedo sia questo il modo giusto di farlo? Controllare il codice è EEXISTil modo giusto per sapere che la cartella esiste già? So che posso fare fs.stat()prima di creare la directory, ma sarebbero già due hit per il filesystem.

In secondo luogo, esiste una documentazione completa o almeno più dettagliata di Node.js che contiene dettagli su cosa contengono gli oggetti di errore, quali parametri indicano ecc.


31
Piccolo nitpick, ma sbarazzarsi di e &&. Se !efallisce, allora sai che eè vero.
I Hate Lazy,

Risposte:


236

Un buon modo per farlo è usare il modulo mkdirp .

$ npm install mkdirp

Usalo per eseguire la funzione che richiede la directory. Il callback viene chiamato dopo la creazione del percorso o se il percorso esiste già. L'errore errviene impostato se mkdirp non è riuscito a creare il percorso della directory.

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

    // path exists unless there was an error

});

3
Mi sembra che la risposta corretta (leggi "nessuna dipendenza aggiunta") sarebbe quella in basso, di @Raugaral, usando fs.exists(Sync).
Ricardo Pedroni,

@meawoppl, è 'makedirectory'p. La "p" non è nota.
Andrew

4
@RicardoPedroni Il modo corretto è usare un modulo. I moduli di solito cercano con tutto il cuore di risolvere un problema e vengono spesso mantenuti. Puoi aggiornarli facilmente con npm. Inoltre, dovresti specificamente evitare di usare fs.exists [Sync] poiché il suo utilizzo implica condizioni di gara.
1o gennaio

16
@ 1j01 Non credo che il modo corretto sia usare un modulo se la piattaforma supporta nativamente l'operazione. Questa è una strada per il caos. Sono d'accordo che ci sono risposte migliori dal punto di vista tecnico.
c ..

2
@ 1j01 Inoltre, l'uso delle operazioni di sincronizzazione implica condizioni di gara perché il loro uso è una soluzione per loro.
c ..

193

Modifica: poiché questa risposta è molto popolare, l'ho aggiornata per riflettere le pratiche aggiornate.

Nodo> = 10

La nuova { recursive: true }opzione di Node fsora lo consente in modo nativo. Questa opzione imita il comportamento di UNIX mkdir -p. Si assicurerà in modo ricorsivo che ogni parte del percorso esista e non genererà un errore se ce ne sono.

(Nota: potrebbe comunque generare errori come EPERMo EACCESS, quindi meglio ancora racchiuderlo in try {} catch (e) {}se l'implementazione è suscettibile ad essa.)

Versione sincrona.

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

Versione asincrona

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

Versioni precedenti del nodo

Usando a try {} catch (err) {}, puoi ottenerlo con garbo senza incontrare una condizione di razza.

Al fine di prevenire i tempi morti tra il controllo dell'esistenza e la creazione della directory, proviamo semplicemente a crearla e ignorare l'errore se presente EEXIST(directory già esistente).

Se l'errore non è EEXIST, tuttavia, dovremmo generare un errore, perché potremmo avere a che fare con qualcosa come un EPERMoEACCES

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

Per mkdir -p-come comportamento ricorsivo, per esempio ./a/b/c, che avrebbe dovuto chiamare in ogni parte del dirpath, ad esempio ./a, ./a/b,.a/b/c


var fs = Npm.require ('fs'); var dir = process.env.PWD + '/ files / users /' + this.userId + '/'; provare {fs.mkdirSync (dir); } catch (e) {if (e.code! = 'EEXIST') lancio e; }
Aaron,

Ho provato il tuo codice, ho creato uno script js che utilizza la creazione del catalogo in questo modo: mkdirpSync (path.join (__ dirname, 'first', 'second', 'third', 'ololol', 'works')); Ma ho ottenuto questo errore: $ node 1.js fs.js: 747 return binding.mkdir (pathModule._makeLong (path), ^ Error: EPERM, operazione non consentita 'C: \' in Error (native) in Object.fs. mkdirSync (fs.js: 747: 18) su mkdirpSync (C: \ Users \ MAXIM \ Desktop \ test \ 1.js: 15: 8) su Object. <anonimo> (C: \ Users \ MAXIM \ Desktop \ test \ 1.js: 19: 1) ... Potresti suggerire cosa potrebbe esserci di sbagliato? Utilizzato su Windows ovviamente :)
Alendorff

L'EPERM sembra un problema di autorizzazione, quindi la sceneggiatura non avrebbe comunque interrotto l'esecuzione
Christophe Marois,

Penso che sarebbe meglio: 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 (errore) {if (error.code! = 'EEXIST') {errore di lancio; }}}}
manish

1
attenzione: non funziona se il tuo percorso inizia con a /
acemtp


26

I documenti node.js per fs.mkdirsostanzialmente rimandano alla pagina man di Linux per mkdir(2). Ciò indica che EEXISTverrà indicato anche se il percorso esiste ma non è una directory che crea un caso angolare imbarazzante se segui questa strada.

Potrebbe essere meglio chiamare fs.statche ti dirà se il percorso esiste e se si tratta di una directory in una singola chiamata. Per (quello che presumo sia) il caso normale in cui la directory esiste già, è solo un singolo hit del filesystem.

Questi fsmetodi del modulo sono wrapper sottili attorno alle API C native, quindi è necessario controllare le pagine man a cui si fa riferimento nei documenti node.js per i dettagli.


19
Chiamare statprima mkdirha il potenziale per una condizione di razza - tienilo a mente.
Roger Lipscombe,

24

Puoi usare questo:

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");
        }
    });
}

1
-1. Non credo che funzioni, statSyncgenererà un errore se l'entità non esiste affatto, bloccando il codice. Devi avvolgerlo in un try/catchblocco.
Chris Foster,

2
Scusa ho sbagliato. cambia "statSync" per "existSync"
Raugaral

5
Secondo nodejs.org/api/fs.html#fs_fs_mkdirsync_path_mode la variante Sync di mkdir non accetta un callback
danwellman,

1
Secondo nodejs.org/api/fs.html#fs_fs_existssync_path , fs.existsSync()e fs.exists()sarà deprecato.
pau.moreno,

7

Propongo una soluzione senza moduli (accumulare moduli non è mai raccomandato per manutenibilità soprattutto per le piccole funzioni che possono essere scritte in poche righe ...):

ULTIMO AGGIORNAMENTO :

Nella v10.12.0, le opzioni ricorsive di impletement di NodeJS:

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

AGGIORNARE :

// 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');

fs.exists()è obsoleto nel nodo v9. usa fs.access()invece. (ritorna undefinedse il file esiste; altrimenti genera un errore ENOENT)
chharvey,

Senza alcun pacchetto npm, funziona. È un codice prezioso. Grazie
Karthik Sridharan il

Questo è abbastanza meglio per creare una cartella sotto un lungo percorso esistente;) Grazie, amico.
Tsung Goh,

1
Che dire fs.mkdirSync('my/new/folder/create', {recursive: true})?
saitho

Grazie ! Aggiornamento il mio post per aiutare gli altri. Il nodo 10.12.0 era troppo recente.
Liberateur


4

Ecco il codice ES6 che utilizzo per creare una directory (quando non esiste):

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}`)
});

Nota:

  • All'inizio della createDirectoryfunzione, normalizzo il percorso per garantire che il tipo di separatore di percorso del sistema operativo verrà utilizzato in modo coerente (ad esempio questo si trasformerà C:\directory/testin C:\directory\test(quando si è su Windows)
  • fs.existsè deprecato , ecco perché uso fs.statper verificare se la directory esiste già
  • Se non esiste una directory, il codice di errore sarà ENOENT( E rror NO ENT ry)
  • La directory stessa verrà creata utilizzando fs.mkdir
  • Preferisco la funzione asincrona fs.mkdirrispetto alla sua controparte bloccante fs.mkdirSynce grazie al wrapping Promisesarà garantito che il percorso della directory verrà restituito solo dopo che la directory è stata creata correttamente

Grazie per una soluzione pulita che non prevede moduli non necessari. Ha funzionato perfettamente per me. Vorrei che ci fossero più risposte come questa!
Ken Lyon

3

A mio parere, è meglio non contare gli hit del filesystem mentre si codifica in Javascript. Tuttavia, (1) stat& mkdire (2) mkdire controllare (o scartare) il codice di errore, entrambi i modi sono i modi giusti per fare quello che vuoi.


-1, non vedo come sia il controllo che lo scarto possano essere entrambi i modi giusti per farlo. Questa è praticamente una non risposta.
Matt Ball,

È un buon modo per mkdir una directory o usare quella esistente. Non vedo perché non vedi. Controllare il codice di errore è educato, mentre scartare il codice di errore è solo buono. non sei d'accordo?
Chul-Woong Yang,

1
Forse questo è un problema di barriera linguistica, ma ho letto questo come non rispondere alla domanda che l'OP sta ponendo.
Matt Ball,

Vedo qual è il tuo punto. Tuttavia, credo che ci siano molti modi per fare le cose nel modo giusto. Grazie.
Chul-Woong Yang,

2

crea una directory di nomi dinamici per ogni utente ... usa questo codice

***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");
}

1

Puoi fare tutto questo con il modulo File System.

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.
})

Non hai nemmeno bisogno di controllare se la directory esiste. Il codice seguente garantisce inoltre che la directory sia già esistente o creata.

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.
})

0

La risposta di Raugaral ma con funzionalità -p. Brutto, ma funziona:

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

0

Proprio come una nuova alternativa alla risposta di Teemu Ikonen , che è molto semplice e facilmente leggibile, è usare il ensureDirmetodo del fs-extrapacchetto.

Non può essere utilizzato solo come sostituto palese del fsmodulo integrato, ma ha anche molte altre funzionalità oltre alle funzionalità del fspacchetto.

Il ensureDirmetodo, come suggerisce il nome, garantisce l'esistenza della directory. Se la struttura della directory non esiste, viene creata. Come mkdir -p. Non solo la cartella finale, ma l'intero percorso viene creato se non esiste già.

quella fornita sopra è la asyncversione di esso. Ha anche un metodo sincrono per eseguire ciò nella forma del ensureDirSyncmetodo.


0

La risposta di @ Liberateur sopra non ha funzionato per me (Nodo v8.10.0). Poche modifiche hanno funzionato, ma non sono sicuro che sia la strada giusta. Per favore, suggerisci

// 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');
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.