Node.js创建文件夹或使用现有文件夹


186

我已经阅读了Node.js的文档,除非我错过了一些内容,否则它不会告诉您某些操作(特别是)中包含的参数fs.mkdir()。正如您在文档中看到的那样,它不是很多。

当前,我有以下代码,该代码尝试创建一个文件夹或使用现有的文件夹:

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

但是我想知道这是正确的方法吗?检查代码EEXIST是否正确知道文件夹已存在?我知道我可以fs.stat()在创建目录之前执行此操作,但这已经是对文件系统的两次命中。

其次,是否有Node.js的完整或至少是更详细的文档,其中包含有关错误对象包含的内容,参数指示的内容等的详细信息。


31
小nitpick,但摆脱e &&。如果!e失败,那么您知道e是真的。
我讨厌懒惰的2012年

Answers:


236

做到这一点的好方法是使用mkdirp模块。

$ npm install mkdirp

使用它来运行需要目录的功能。创建路径后或路径已经存在时调用回调。err如果mkdirp无法创建目录路径,则会设置错误。

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

    // path exists unless there was an error

});

3
在我看来,正确的答案(读为“不添加依赖项”)应该是@Raugaral使用的低位答案fs.exists(Sync)
里卡多·佩德罗尼

@meawoppl,它是“ makedirectory” p。'p'是未知的。
安德鲁(Andrew)2015年

4
@RicardoPedroni正确的方法是使用模块。模块通常全心全意地试图解决一个问题,并且经常得到维护。您可以使用npm轻松更新它们。另外,您应该特别避免使用fs.exists [Sync],因为它的使用暗示了竞争条件。
2015年

16
@ 1j01我不相信正确的方法是在平台本地支持该操作的情况下使用模块。那是通往混乱的道路。我必须同意,从技术角度来看,会有更好的答案。
c ^ ..

2
@ 1j01另外,使用同步操作暗含竞争条件,因为使用竞争条件可以解决它们。
c ^ ..

193

编辑: 因为此答案非常受欢迎,所以我对其进行了更新以反映最新的做法。

节点> = 10

现在{ recursive: true },Node's 的新选项fs本身允许这样做。此选项模仿UNIX的行为mkdir -p。它将递归地确保路径的每个部分都存在,并且如果有任何一个都不会引发错误。

(注意:它可能仍会引发诸如EPERM或的错误EACCESS,因此,try {} catch (e) {}如果您的实现容易受到影响,最好还是将其包装在中。)

同步版本。

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

异步版本

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

较旧的节点版本

使用try {} catch (err) {},您可以非常优雅地实现此目标,而不会遇到竞争状况。

为了防止在检查存在和创建目录之间出现停滞时间,我们只是简单地尝试直接创建它,而忽略该错误(如果EEXIST目录已经存在)。

EEXIST但是,如果错误不是,我们应该抛出错误,因为我们可能会处理诸如EPERMEACCES

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

对于mkdir -p样递归的行为,例如./a/b/c,你必须把它在dirpath的每一个部分,例如./a./a/b.a/b/c


var fs = Npm.require('fs'); var dir = process.env.PWD +'/ files / users /'+ this.userId +'/'; 尝试{fs.mkdirSync(dir); } catch(e){if(e.code!='EEXIST')throw e; }
亚伦

我尝试了您的代码,创建了一个使用目录创建的js脚本,如下所示:mkdirpSync(path.join(__ dirname,'first','second','third','ololol','works'))); 但是得到了这个错误:$ node 1.js fs.js:747 return binding.mkdir(pathModule._makeLong(path),^错误:EPERM,在Object.fs的Error(native)处不允许'C:\'操作。对象处的mkdirpSync(C:\ Users \ MAXIM \ Desktop \ test \ 1.js:15:8)中的mkdirSync(fs.js:747:18)。<匿名>(C:\ Users \ MAXIM \ Desktop \ test \ 1.js:19:1)...您能建议出什么问题吗?显然在Windows上使用:)
Alendorff

EPERM似乎是一个权限问题,因此该脚本无论如何都不会中断执行
Christophe Marois 2015年

我认为这样会更好:var mkdirpSync = function(dirpath){var parts = dirpath.split(path.sep); for(var i = 1; i <= parts.length; i ++){试试{fs.mkdirSync(path.join.apply(null,parts.slice(0,i))); } catch(error){if(error.code!='EEXIST'){引发错误;}
manish

1
警告:如果您的路径以/
acemtp '16


26

的node.js文档fs.mkdir基本上遵循的Linux手册页mkdir(2)。这表示EEXIST如果存在该路径,但也不会显示该目录,如果您走这条路线,该目录不会创建笨拙的极端情况。

您最好调用fs.stat,它会告诉您该路径是否存在以及它是否是单个调用中的目录。对于(我假设是)目录已经存在的正常情况,它只是一个文件系统命中。

这些fs模块方法是本机C API的精简包装,因此您必须检查一下node.js文档中引用的手册页以获取详细信息。


19
stat提前致电mkdir可能会导致比赛状态-请记住这一点。
罗杰·利普斯科姆

24

您可以使用此:

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。我不认为这行得通,statSync如果该实体根本不存在,将抛出错误,从而使代码崩溃。您需要将其包装在一个try/catch块中。
克里斯·福斯特

2
对不起,我错了。将“ statSync”更改为“ existsSync”
Raugaral 2014年


1
nodejs.org/api/fs.html#fs_fs_existssync_pathfs.existsSync()并且fs.exists()将被弃用。
pau.moreno 2015年

7

我提出了一个不带模块的解决方案(从不建议使用累积模块来提高可维护性,尤其是对于可以用几行编写的小功能...):

最后更新 :

在v10.12.0中,NodeJS实现递归选项:

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

更新:

// 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()在节点v9中已弃用。使用fs.access()代替。(undefined如果文件存在则返回;否则抛出错误ENOENT
chharvey

没有任何npm软件包,它就可以工作。这是一个有价值的代码。谢谢
Karthik Sridharan '18

这对于在现有的长路径下创建文件夹来说是比较好的;)谢谢,伙计。
宗悟

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

谢谢 !我更新我的帖子以帮助他人。节点10.12.0太新了。
Liberateur


4

这是我用来创建目录的ES6代码(当它不存在时):

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

注意:

  • createDirectory函数开始时,我对路径进行规范化,以确保操作系统的路径分隔符类型将始终使用(例如,在Windows上,它将C:\directory/test变成C:\directory\test())
  • fs.exists弃用,这就是为什么我fs.stat用来检查目录是否已经存在的原因
  • 如果目录不存在,则错误代码为ENOENTE rror NO ent ry)
  • 目录本身将使用创建 fs.mkdir
  • 我更喜欢异步函数fs.mkdir而不是阻塞函数fs.mkdirSync,因为Promise它具有环绕功能,因此可以确保仅在成功创建目录后才返回目录路径

感谢您提供不涉及不必要模块的干净解决方案。它对我来说很完美。我希望有更多这样的答案!
肯·里昂

3

我认为,使用Javascript编码时,最好不要计算文件系统的命中率。但是,(1)statmkdir(2)mkdir和支票(或丢弃)错误代码,这两种方式都是你想要做什么正确的方法。


-1,我看不到检查或丢弃都是正确的方法。这几乎是一个无答案的问题。
马特·鲍尔

这是mkdir目录或使用现有目录的好方法。我不明白为什么你看不到。检查错误代码是有礼貌的,而丢弃错误代码只是一个好方法。你不同意吗?
杨楚雄

1
也许这是一个语言障碍问题,但是我读这是因为它没有回答OP提出的问题。
马特·鲍尔

我明白你的意思了。但是,我相信有很多方法可以正确处理事情。谢谢。
杨楚雄

2

为每个用户创建动态名称目录...使用此代码

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

您可以使用文件系统模块来完成所有这些操作。

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

您甚至根本不需要检查目录是否存在。以下代码还保证目录已经存在或已创建。

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

Raugaral的答案,但具有-p功能。丑陋,但有效:

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

正如Teemu Ikonen的答案的一种较新的替代方法一样,它非常简单且易于阅读,它就是使用软件包的ensureDir方法fs-extra

它不仅可以用作内置fs模块的公然替代品,而且除了fs包装的功能外,还具有许多其他功能。

ensureDir顾名思义,该方法可确保目录存在。如果目录结构不存在,则会创建它。像mkdir -p。不只是结束文件夹,如果还不存在,则会创建整个路径。

上面提供的是async它的版本。它还具有同步方法,以方法的形式执行此操作ensureDirSync


0

上面 @Liberateur 的答案对我不起作用(Node v8.10.0)。稍加修改即可解决问题,但我不确定这是否正确。请提出建议。

// 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');
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.