2011-10-24 16 views
9

私は、ファイルをダウンロードし、それに送信されたパラメータに基づいてネストされたディレクトリ構造に保存する関数を持っています(例:./somedir/a/b/c or ./ somedir2/a/d/b)。途中のディレクトリが作成されているとは信じられないので、存在しない場合は、ファイルパスに沿って各ディレクトリをチェックして作成する必要があります。さて、ノード0.4.xでは完璧に動作するいくつかのコードがありますが、ノード0.5.x(少なくとも0.5.10でテスト済み)のWindowsバージョンでは何かが壊れています。Node.jsの再帰的ディレクトリの作成0.5.x

私はファイルシステムを理解するのがひどいので、誰かがこの作業をどのように行うか、それと同様に動作する他のものと置き換えることができたら、私は非常に感謝しています。目標は、ノード0.4.xと0.5.xだけでなく、UnixとWindowsの両方で適切に機能するコードを持つことです。

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

使用例:

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

EDIT:それは私自身の質問に答えるという愚かな感じが、私はように見える

# 
# 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

私は、OSがWindows 'VARウィンドウ= _path.indexOf( '\\')であれば決定異なる分岐ロジックを使用して試してみました> = 0; '、しかし私はまだENOENTエラーを取得しています。私が知ることから、fs.statはerrno 32でエラーを返しています。これによりコードが失敗します。 – geoffreak

+0

もう少し調べてみると、fs.statについて何か不安なので、[githubに関する問題](https://github.com/joyent/node/issues/1927)を投稿しました。 – geoffreak

答えて

6

ノード-FS(https://npmjs.org/package/node-fs)を見てみましょう:

$ npm install ensureDir 

でインストールすることができるhttps://github.com/samxxu/ensureDirは、ここで完全なソースコードです。

node-fsは、元のnodejs fsライブラリの拡張であり、再帰的なディレクトリ作成などの新しい機能を提供します。

+1

これは素晴らしいことです...私が見る限り、操作が非同期で行えるようにする唯一の答えです。 – UpTheCreek

+0

あなたはNode.fsでそれを行う方法を教えてください? –

0

:(CoffeeScriptの中に)ノード0.8.xの更新それを分かってください。プラットフォーム間の互換性を保証するために、__dirnameに基づいて相対パスを使用するようにしてください。誰かがこの問題を発見したら、私に知らせてください。私はWindows(0.5.10)と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

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

用法:

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

これは私にとってはうまくいきましたが、ハードコーディングされたUNIXパス区切り記号をノードのクロスプラットフォームパス区切り定数で変更する必要がありました。答えを修正するのではなく、その要点を作成しました。https://gist.github.com/3960169 –

+0

ああ、忘れてしまった! – alzclarke

+0

いいですが、それは同期的です。 – UpTheCreek

5

私は、ユーザーが自分のフォルダに自分の写真をアップロードすることができますウェブサイトを持っています。私はディレクトリを再帰的に作成するための良いオープンソースモジュールを見つけることができなかったので、実装しました。

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

最も効率的な非同期バージョンと思われます。トップダウンで動作するので、ボトムアップから不必要に存在するコールは発生しません。 (すなわち、最小量のシステムコールを行う)。 – Aktau

0

これも機能します。反復的、非再帰的、アルゴリズム。

`` `

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

これは私がそれを得ることができると同じくらいきれいです展開サーバーのために、このの本当に小さなバージョンを持つ必要がありました。

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

CoffeeScriptのコード

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

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