windows Node.js 0.5.x 的递归目录创建

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7871058/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 18:20:22  来源:igfitidea点击:

Recursive directory creation for Node.js 0.5.x

windowsnode.jsfile-io

提问by geoffreak

I have a function that downloads a file and saves it in a nested directory structure based on parameters sent to it (ex: ./somedir/a/b/c or ./somedir2/a/d/b). I cannot trust that any directory along the way has been created so I need to have each directory along the filepath checked and created if it doesn't exist. Now, I have some code that works perfectly for Node 0.4.x, but something has broken in at least the Windows version of Node 0.5.x (tested on 0.5.10 specifically).

我有一个函数可以下载文件并根据发送给它的参数将其保存在嵌套目录结构中(例如:./somedir/a/b/c 或 ./somedir2/a/d/b)。我无法相信沿途的任何目录都已创建,因此我需要检查并创建文件路径中的每个目录(如果它不存在)。现在,我有一些非常适合 Node 0.4.x 的代码,但至少在 Node 0.5.x 的 Windows 版本中出现了问题(专门在 0.5.10 上测试)。

I am terrible with understanding filesystems, so if someone could figure out how I could make this work or replace it with something else that works similarly, I would very much appreciate it. The goal is to have code that would function properly on both Unix and Windows as well as Node 0.4.x and 0.5.x.

我对文件系统的理解很糟糕,所以如果有人能弄清楚我如何使这个工作或用其他类似的东西替换它,我将非常感激。目标是让代码能够在 Unix 和 Windows 以及 Node 0.4.x 和 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);
};

Example Usage:

示例用法:

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

EDIT: Update for Node 0.8.x (in CoffeeScript):

编辑:节点 0.8.x 的更新(在 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

采纳答案by bpedro

Take a look at node-fs (https://npmjs.org/package/node-fs).

看看 node-fs ( https://npmjs.org/package/node-fs)。

node-fs is an extension to the original nodejs fs library, offering new functionalities, such as recursive directory creation.

node-fs 是原始 nodejs fs 库的扩展,提供了新功能,例如递归目录创建。

回答by alzclarke

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

usage:

用法:

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

回答by Sam X. Xu

I have a website which allows users upload their photo into their own folder. I could not find a good open source module to create directories recursively, so I implemented one. https://github.com/samxxu/ensureDir,which can be installed by

我有一个网站,允许用户将他们的照片上传到他们自己的文件夹中。我找不到一个好的开源模块来递归创建目录,所以我实现了一个。https://github.com/samxxu/ensureDir,可以通过安装

$ npm install ensureDir

Here is the full source code:

这是完整的源代码:

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

回答by holly

make a synchronous version base on geoffreak's.

制作基于geoffreak 的同步版本。

thanks for geoffreak.

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

回答by geoffreak

It feels rather silly answering my own question, but I seem to have it figured out. Just make sure you use relative paths based off of __dirname to ensure cross-platform compatibility. If anyone spots any issues with this please let me know. I have tested it on Windows (0.5.10) and Mac (0.4.12).

回答我自己的问题感觉很愚蠢,但我似乎已经弄清楚了。只需确保使用基于 __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);
};

回答by Andrea Baccega

Also this works. Iterative, non-recursive, 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 + '/';
    }
}

```

``

回答by Chris Kirby

Had to have a really small version of this for a deployment server this is about as pretty as I could get it.

必须为部署服务器提供一个非常小的版本,这与我所能得到的一样漂亮。

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

回答by Aliaksandr

# npm install -g node-fs

# npm install -g node-fs

coffeeScript code:

咖啡脚本代码

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

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