2011-10-24 13 views
9

Ho una funzione che scarica un file e lo salva in una struttura di directory annidata sulla base di parametri inviati ad esso (es: ./somedir/a/b/c o ./ somedir2/a/d/b). Non riesco a credere che qualsiasi directory lungo il percorso è stato realizzato in modo da ho bisogno di avere ogni directory lungo il percorso file controllato e creato se non esiste. Ora, ho qualche codice che funziona perfettamente per Node 0.4.x, ma qualcosa si è rotto in almeno la versione per Windows del Nodo 0.5.x (testato su 0.5.10 specifico).ricorsiva creazione di directory per Node.js 0.5.x

Sono terribile con la comprensione dei filesystem, quindi se qualcuno riuscisse a capire come potrei fare questo lavoro o sostituirlo con qualcos'altro che funziona allo stesso modo, lo apprezzerei molto. L'obiettivo è quello di avere un codice che funzioni correttamente sia su Unix che su Windows, come pure sul nodo 0.4.xe 0.5.x.

// automatically create directories if they do not exist at a path 
function mkdirs(_path, mode, callback) { 
    var dirs = _path.split("/"); 
    var walker = [dirs.shift()]; 

    var walk = function (ds, acc, m, cb) { 
    if (ds.length > 0) { 
     var d = ds.shift(); 
     acc.push(d); 
     var dir = acc.join("/"); 

     fs.stat(dir, function (err, stat) { 
     if (err) { 
      // file does not exist 
      if (err.errno == 2) { 
      fs.mkdir(dir, m, function (erro) { 
       if (erro && erro.errno != 17) { 
       terminal.error(erro, "Failed to make " + dir); 
       return cb(new Error("Failed to make " + dir + "\n" + erro)); 
       } else { 
       return walk(ds, acc, m, cb); 
       } 
      }); 
      } else { 
      return cb(err); 
      } 
     } else { 
      if (stat.isDirectory()) { 
      return walk(ds, acc, m, cb); 
      } else { 
      return cb(new Error("Failed to mkdir " + dir + ": File exists\n")); 
      } 
     } 
     }); 
    } else { 
     return cb(); 
    } 
    }; 
    return walk(dirs, walker, mode, callback); 
}; 

Esempio di utilizzo:

mkdirs('/path/to/file/directory/', 0777, function(err){ 

EDIT: Aggiornamento per Nodo 0.8.x (in CoffeeScript):

# 
# Function mkdirs 
# Ensures all directories in a path exist by creating those that don't 
# @params 
# path:  string of the path to create (directories only, no files!) 
# mode:  the integer permission level 
# callback: the callback to be used when complete 
# @callback 
# an error object or false 
# 
mkdirs = (path, mode, callback) -> 
    tryDirectory = (dir, cb) -> 
    fs.stat dir, (err, stat) -> 
     if err #the file doesn't exist, try one stage earlier then create 
     if err.errno is 2 or err.errno is 32 or err.errno is 34 
      if dir.lastIndexOf("/") is dir.indexOf("/") #only slash remaining is initial slash 
      #should only be triggered when path is '/' in Unix, or 'C:/' in Windows 
      cb new Error("notfound") 
      else 
      tryDirectory dir.substr(0, dir.lastIndexOf("/")), (err) -> 
       if err #error, return 
       cb err 
       else #make this directory 
       fs.mkdir dir, mode, (error) -> 
        if error and error.errno isnt 17 
        cb new Error("failed") 
        else 
        cb() 
     else #unkown error 
      cb err 
     else 
     if stat.isDirectory() #directory exists, no need to check previous directories 
      cb() 
     else #file exists at location, cannot make folder 
      cb new Error("exists") 
    path = (if path.indexOf("\\") >= 0 then path.replace("\\", "/") else path) #change windows slashes to unix 
    path = path.substr(0, path.length - 1) if path.substr(path.length - 1) is "/" #remove trailing slash 
    tryDirectory path, callback 
+0

Ho provato con logica diversa suddivisione determinato se il sistema operativo è Windows 'finestre var = _path.indexOf ('\\')> = 0; ', ma sto ancora ottenendo errori ENOENT. Da quello che posso dire, fs.stat restituisce un errore con errno 32, che causa il fallimento del codice. – geoffreak

+0

Dopo aver fatto ulteriori ricerche, sembra che qualcosa non funzioni su fs.stat, quindi ho inviato un [problema su github] (https://github.com/joyent/node/issues/1927). – geoffreak

risposta

6

Date un'occhiata al nodo-fs (https://npmjs.org/package/node-fs).

nodo-fs è un'estensione alla libreria i nodejs originali FS, offrendo nuove funzionalità, come ad esempio la creazione di directory ricorsiva.

+1

È fantastico! ... l'unica risposta qui che consente di eseguire l'operazione asincrona per quanto posso vedere. – UpTheCreek

+0

Non dirci come farlo con Node.fs? –

0

Ci si sente un po 'sciocco rispondere alla mia domanda, ma mi sembra di aver capito. Assicurati di utilizzare percorsi relativi basati su __dirname per garantire la compatibilità multipiattaforma. Se qualcuno dovesse riscontrare problemi con questo per favore fammi sapere. L'ho provato su Windows (0.5.10) e Mac (0.4.12).

// automatically create directories if they do not exist at a path 
function mkdirs(path, mode, callback){ 
    var path = path.indexOf('\\') >= 0 ? path.replace('\\', '/') : path;//change windows slashes to unix 
    if (path.substr(path.length - 1) == '/') { //remove trailing slash 
     path = path.substr(0, path.length - 1); 
    } 
    function tryDirectory(dir, cb){ 
     fs.stat(dir, function (err, stat) { 
      if (err) { //the file doesn't exist, try one stage earlier then create 
       if (err.errno == 2 || err.errno == 32) { 
        if (dir.lastIndexOf('/') == dir.indexOf('/')) {//only slash remaining is initial slash 
         //should only be triggered when path is '/' in Unix, or 'C:/' in Windows 
         cb(new Error('notfound')); 
        } 
        else { 
         tryDirectory(dir.substr(0, dir.lastIndexOf('/')), function(err){ 
          if (err) { //error, return 
           cb(err); 
          } 
          else { //make this directory 
           fs.mkdir(dir, mode, function (error) { 
            if (error && error.errno != 17) { 
             console.log("Failed to make " + dir); 
             return cb(new Error('failed')); 
            } else { 
             cb(); 
            } 
           }); 
          } 
         }); 
        } 
       } 
       else { //unkown error 
        console.log(util.inspect(err, true)); 
        cb(err); 
       } 
      } 
      else { 
       if (stat.isDirectory()) { //directory exists, no need to check previous directories 
        cb(); 
       } 
       else { //file exists at location, cannot make folder 
        return cb(new Error('exists')); 
       } 
      } 
     }); 
    } 
    tryDirectory(path, callback); 
}; 
1

creare una versione sincrona su geoffreak.

grazie per geoffreak.

function mkdirs(path, mode, callback){ 
    var path = path.indexOf('\\') >= 0 ? path.replace(/\\/g, '/') : path;//change windows slashes to unix 
    if (path.substr(path.length - 1) == '/') { //remove trailing slash 
     path = path.substr(0, path.length - 1); 
    } 
    console.log('path is:' + path); 

    function tryDirectory(dir, cb){ 
     console.log('path is:' + dir); 
     var stat ; 
     try { 
      stat = fs.statSync(dir) ; 

      // the file exist 
      if (stat.isDirectory()) { //directory exists, no need to check previous directories 
       cb(); 
      } 
      else { //file exists at location, cannot make folder 
       return cb(new Error('exists')); 
      } 

     } 
     catch(err) 
     { 
      if (err) { //the file doesn't exist, try one stage earlier then create 
       console.log('failed to get stat of ' + dir + ', errno is :' + err.errno); 
       if (err.errno == 2 || err.errno == 32 || err.errno == 34) { 

        //if (dir.lastIndexOf('/') == dir.indexOf('/')) {//only slash remaining is initial slash 
         //should only be triggered when path is '/' in Unix, or 'C:/' in Windows 
         //cb(new Error('notfound')); 
        //} 
        if (dir.length < 2) { 
         cb(new Error('invalid_path')); 
        } 
        else { 
         // try one stage earlier then create 
         tryDirectory(dir.substr(0, dir.lastIndexOf('/')), function(err){ 
          if (err) { //error, return 
           cb(err); 
          } 
          else { //make this directory 
           try { 
            fs.mkdirSync(dir, mode); 

            console.log('make dir ok, dir:' + dir); 
            cb();         
           } 
           catch (error) { 
            if (error && error.errno != 17) { 
             console.log("Failed to make " + dir); 
             return cb(new Error('failed')); 
            } 
           }         
          } 
         }); 
        } 
       } 
       else { //unkown error 
        console.log(util.inspect(err, true)); 
        cb(err); 
       } 
      } 

     } 

    } 
    tryDirectory(path, callback); 
}; 
12
function mkdir(path, root) { 

    var dirs = path.split('/'), dir = dirs.shift(), root = (root || '') + dir + '/'; 

    try { fs.mkdirSync(root); } 
    catch (e) { 
     //dir wasn't made, something went wrong 
     if(!fs.statSync(root).isDirectory()) throw new Error(e); 
    } 

    return !dirs.length || mkdir(dirs.join('/'), root); 
} 

utilizzo:

var fs = require('fs'); 
mkdir('parent/child/grandchild'); 
+3

Questo ha funzionato perfettamente per me, tuttavia ho dovuto modificare i separatori di percorso UNIX codificati con la costante del separatore dei percorsi multipiattaforma di Node. Piuttosto che modificare la risposta, ho creato una sintesi per esso https://gist.github.com/3960169 –

+0

ah sì, ho dimenticato! – alzclarke

+0

Bello, ma un peccato è sincrono – UpTheCreek

5

Ho un sito web che permette agli utenti di caricare le loro foto nel loro propria cartella. Non sono riuscito a trovare un buon modulo open source per creare directory in modo ricorsivo, quindi l'ho implementato. https://github.com/samxxu/ensureDir, che può essere installato da

$ npm install ensureDir 

Ecco il codice sorgente completo:

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

/** 
* ensure a directory exists, create it recursively if not. 
* 
* @param dir The directory you want to ensure it exists 
* @param mode Refer to fs.mkdir() 
* @param callback 
*/ 
module.exports = function ensureDir(dir, mode, callback) { 
    if (mode && typeof mode === 'function') { 
    callback = mode; 
    mode = null; 
    } 

    mode = mode || 0777 & (~process.umask()); 

    callback = callback || function() { 
    }; 

    _ensureDir(dir, mode, callback); 
} 

function _ensureDir(dir, mode, callback) { 
    var existsFunction = fs.exists || path.exists; 

    existsFunction(dir, function (exists) { 
    if (exists) return callback(null); 

    var current = path.resolve(dir); 
    var parent = path.dirname(current); 

    _ensureDir(parent, mode, function (err) { 
     if (err) return callback(err); 

     fs.mkdir(current, mode, function (err) { 
     if (err) return callback(err); 
     callback(); 
     }); 
    }); 
    }); 
} 
+0

Sembra essere la versione più efficiente e asincrona. Funziona dall'alto verso il basso in modo che non vengano effettuate chiamate inutili dal basso verso l'alto. (es .: effettua la quantità minima di chiamate di sistema). – Aktau

0

Anche questo funziona. Igoativo, non ricorsivo, algo.

`` `

function mkdirs(path) { 
    var dirs = path.split('/'); 
    var prevDir = dirs.splice(0,1)+"/"; 
    while(dirs.length > 0) { 
     var curDir = prevDir + dirs.splice(0,1); 
     if (! fs.existsSync(curDir)) { 
      fs.mkdirSync(curDir); 
     } 
     prevDir = curDir + '/'; 
    } 
} 

` ``

0

doveva avere una molto piccola versione di questo per un server di distribuzione si tratta di bella come ho potuto farlo.

function mkdirs(file){ 
    var dirs, paths=[]; 
    dirs = file.split('/'); 
    while(dirs.length>1){ 
     paths.push(dirs.shift()); 
     var tmp = paths.join('/'); 
     if(!fs.existsSync('/'+tmp)) fs.mkdirSync('/'+tmp); 
    } 
} 
0

# npm install -g node-fs

codice CoffeeScript:

String::dirReAdd = -> 
    require('node-fs').mkdirSync(@.toString(), 0o777, true) 
    @ 

# './tmp2/example_sync/first/second/third/fourth/fifth/'.dirReAdd().pr() 
Problemi correlati