212

我已经阅读过 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 文档,其中包含有关错误对象包含的内容、参数表示的内容等详细信息。

4

14 回答 14

248

编辑: 因为这个答案很受欢迎,我已经更新了它以反映最新的做法。

节点 >=10

{ recursive: true }Node 的新选项fs现在允许本机这样做。此选项模仿 UNIX 的mkdir -p. 它将递归地确保路径的每个部分都存在,并且如果其中任何部分存在,则不会抛出错误。

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

同步版本。

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

异步版本

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

旧节点版本

使用 a try {} catch (err) {},您可以非常优雅地实现这一点,而不会遇到竞争条件。

为了防止检查存在和创建目录之间的死时间,我们简单地尝试直接创建它,如果它存在则忽略错误EEXIST(目录已经存在)。

但是,如果错误不是EEXIST,我们应该抛出一个错误,因为我们可能正在处理类似EPERMor的东西EACCES

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

对于mkdir -p-like 递归行为,例如./a/b/c,您必须在 dirpath 的每个部分都调用它,例如./a, ./a/b,.a/b/c

于 2014-06-19T16:27:25.743 回答
244

这样做的好方法是使用mkdirp模块。

$ npm install mkdirp

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

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

    // path exists unless there was an error

});
于 2012-12-04T05:58:59.140 回答
69

如果你想要一个又快又脏的衬里,使用这个:

fs.existsSync("directory") || fs.mkdirSync("directory");
于 2015-10-21T12:13:08.883 回答
27

node.js 文档fs.mkdir基本上遵循mkdir(2). 这表明EEXIST如果路径存在但不是一个目录,如果你走这条路线,也会指示它会创建一个尴尬的角落案例。

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

这些fs模块方法是原生 C API 的薄包装器,因此您必须查看 node.js 文档中引用的手册页以获取详细信息。

于 2012-12-04T05:45:09.067 回答
25

你可以使用这个:

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");
        }
    });
}
于 2014-03-02T15:11:19.533 回答
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');
于 2017-07-07T15:43:15.290 回答
4

你也可以使用fs-extra,它提供了很多常用的文件操作。

示例代码:

var fs = require('fs-extra')

fs.mkdirs('/tmp/some/long/path/that/prob/doesnt/exist', function (err) {
  if (err) return console.error(err)
  console.log("success!")
})

fs.mkdirsSync('/tmp/another/path')

此处的文档:https ://github.com/jprichardson/node-fs-extra#mkdirsdir-callback

于 2016-09-30T10:24:55.387 回答
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函数的开头,我对路径进行了规范化,以保证操作系统的路径分隔符类型将被一致地使用(例如,这将C:\directory/test变成C:\directory\test(在 Windows 上时)
  • fs.exists弃用,这就是我fs.stat用来检查目录是否已存在的原因
  • 如果目录不存在,错误代码将是ENOENT( E rror NO ENT ry)
  • 目录本身将使用fs.mkdir
  • 我更喜欢异步函数fs.mkdir而不是它的阻塞对应函数,fs.mkdirSync并且由于包装Promise,它将保证只有在成功创建目录后才会返回目录的路径
于 2017-03-23T11:04:03.513 回答
3

在我看来,你最好不要在用 Javascript 编码时计算文件系统命中。但是,(1)statmkdir(2)mkdir并检查(或丢弃)错误代码,这两种方法都是做你想做的事情的正确方法。

于 2012-12-04T04:39:42.413 回答
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");
}
于 2016-10-31T13:00:33.470 回答
1

正如Teemu Ikonen 的答案的更新替代方法一样,它非常简单易读,是使用包的ensureDir方法fs-extra

它不仅可以作为内置fs模块的明目张胆的替代品,而且除了包的功能外,还有很多其他的功能fs

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

上面提供的是async它的版本。它也有一个同步的方法来以方法的形式执行这个ensureDirSync

于 2019-05-31T12:21:36.217 回答
0

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

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.
})
于 2019-10-05T06:49:33.483 回答
0

@Liberateur 上面的回答对我不起作用(节点 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');
于 2020-05-31T07:34:16.987 回答
-1

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
于 2019-01-24T21:31:40.330 回答