我有一个函数可以下载文件并根据发送给它的参数将其保存在嵌套目录结构中(例如:./somedir / a / b / c或./somedir2/a/d/b)。我不能相信沿途的任何目录都已创建,因此我需要检查并创建文件路径中的每个目录(如果它不存在)。现在,我有一些适用于Node 0.4.x的代码,但至少在Windows版本的0.5.x(特别是在0.5.10上测试)中出现了一些问题。
我对理解文件系统非常糟糕,所以如果有人能弄清楚我是如何做到这一点的,或者用类似的其他东西替换它,我会非常感激。目标是使代码能够在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);
};
示例用法:
mkdirs('/path/to/file/directory/', 0777, function(err){
编辑:节点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
答案 0 :(得分: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');
答案 1 :(得分:6)
看一下node-fs(https://npmjs.org/package/node-fs)。
node-fs是原始nodejs fs库的扩展,提供了新的功能,例如递归目录创建。
答案 2 :(得分:5)
我有一个网站,允许用户将照片上传到自己的文件夹中。我找不到一个好的开源模块来递归创建目录,所以我实现了一个。 https://github.com/samxxu/ensureDir,可以通过
安装$ npm install ensureDir
以下是完整的源代码:
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();
});
});
});
}
答案 3 :(得分:1)
根据geoffreak's制作同步版本。
感谢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);
};
答案 4 :(得分:0)
回答我自己的问题感觉很傻,但我似乎想通了。只需确保使用基于__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);
};
答案 5 :(得分: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 + '/';
}
}
```
答案 6 :(得分: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);
}
}
答案 7 :(得分: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()