如何使用节点的fs.mkdirSync创建完整路径?

Dav*_*ith 133 fs node.js

如果它不存在,我正在尝试创建一个完整的路径.

代码如下所示:

var fs = require('fs');
if (!fs.existsSync(newDest)) fs.mkdirSync(newDest); 
Run Code Online (Sandbox Code Playgroud)

只要只有一个子目录(像'dir1'这样的newDest),这个代码就可以运行,但是当有一个类似于''dir1/dir2'的目录路径时,它会失败并显示 错误:ENOENT,没有这样的文件或目录

我希望能够根据需要使用尽可能少的代码行创建完整路径.

我读到fs上有一个递归选项,并尝试这样做

var fs = require('fs');
if (!fs.existsSync(newDest)) fs.mkdirSync(newDest,'0777', true);
Run Code Online (Sandbox Code Playgroud)

我觉得递归创建一个不存在的目录应该很简单.我是否遗漏了某些内容或是否需要解析路径并检查每个目录并创建它(如果它尚不存在)?

我是Node的新手.也许我正在使用旧版本的FS?

Mou*_*eer 299

编辑

NodeJS版本10为两者添加了本机支持,10.12.0mkdir使用mkdirSync选项递归创建目录,如下所示:

fs.mkdirSync(targetDir, { recursive: true });
Run Code Online (Sandbox Code Playgroud)

如果你愿意recursive: true,你可以写

fs.promises.mkdir(targetDir, { recursive: true });
Run Code Online (Sandbox Code Playgroud)

原始答案

如果目录不存在,则递归创建目录!(零依赖)

const fs = require('fs');
const path = require('path');

function mkDirByPathSync(targetDir, { isRelativeToScript = false } = {}) {
  const sep = path.sep;
  const initDir = path.isAbsolute(targetDir) ? sep : '';
  const baseDir = isRelativeToScript ? __dirname : '.';

  return targetDir.split(sep).reduce((parentDir, childDir) => {
    const curDir = path.resolve(baseDir, parentDir, childDir);
    try {
      fs.mkdirSync(curDir);
    } catch (err) {
      if (err.code === 'EEXIST') { // curDir already exists!
        return curDir;
      }

      // To avoid `EISDIR` error on Mac and `EACCES`-->`ENOENT` and `EPERM` on Windows.
      if (err.code === 'ENOENT') { // Throw the original parentDir error on curDir `ENOENT` failure.
        throw new Error(`EACCES: permission denied, mkdir '${parentDir}'`);
      }

      const caughtErr = ['EACCES', 'EPERM', 'EISDIR'].indexOf(err.code) > -1;
      if (!caughtErr || caughtErr && curDir === path.resolve(targetDir)) {
        throw err; // Throw if it's just the last created dir.
      }
    }

    return curDir;
  }, initDir);
}
Run Code Online (Sandbox Code Playgroud)

用法

// Default, make directories relative to current working directory.
mkDirByPathSync('path/to/dir');

// Make directories relative to the current script.
mkDirByPathSync('path/to/dir', {isRelativeToScript: true});

// Make directories with an absolute path.
mkDirByPathSync('/path/to/dir');
Run Code Online (Sandbox Code Playgroud)

演示

试试吧!

说明

  • [更新]该解决方案处理平台特有的错误,如fs Promises APIMac和EISDIREPERM用于Windows.感谢@PediT.,@ JohnQ,@ deed02392,@ robyoder和@Almenon的所有报道评论.
  • 该解决方案处理相对路径和绝对路径.感谢@john评论.
  • 在相对路径的情况下,将在当前工作目录中创建(解析)目标目录.要相对于当前脚本dir解析它们,请传递EACCES.
  • 使用{isRelativeToScript: true}path.sep不仅仅是path.resolve()连接,以避免跨平台问题.
  • 使用/和处理错误,fs.mkdirSync如果抛出以处理竞争条件:另一个进程可能在调用try/catch和之间添加文件fs.existsSync()并导致异常.
    • 实现这一目标的另一种方法是检查文件是否存在然后创建它,即fs.mkdirSync().但这是一种反模式,使代码容易受到竞争条件的影响.感谢@GershomMaes关于目录存在检查的评论.
  • 需要Node v6及更高版本才能支持解构.(如果使用旧的Node版本实现此解决方案时遇到问题,请给我留言)

  • Upvote用于简单,递归的响应,无需额外的库或方法! (4认同)
  • 12行扎实的代码,零依赖,我每次都会拿。 (2认同)

csh*_*ton 76

更强大的答案是使用mkdirp.

var mkdirp = require('mkdirp');

mkdirp('/path/to/dir', function (err) {
    if (err) console.error(err)
    else console.log('dir created')
});
Run Code Online (Sandbox Code Playgroud)

然后继续将文件写入完整路径:

fs.writeFile ('/path/to/dir/file.dat'....
Run Code Online (Sandbox Code Playgroud)


Dee*_*ers 47

fs-extra添加了本机fs模块中未包含的文件系统方法.这是对fs的替代.

安装 fs-extra

$ npm install --save fs-extra

const fs = require("fs-extra");
// Make sure the output directory is there.
fs.ensureDirSync(newDest);
Run Code Online (Sandbox Code Playgroud)

有同步和异步选项.

https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureDir.md

  • 这是最好的答案!无论如何,我们大多数人已经在应用程序中添加了fs-extra. (5认同)

bry*_*mac 45

一种选择是使用shelljs模块

npm install shelljs

var shell = require('shelljs');
shell.mkdir('-p', fullPath);
Run Code Online (Sandbox Code Playgroud)

从该页面:

可用选项:

p:完整路径(如有必要,将创建中间目录)

正如其他人所指出的那样,还有其他更集中的模块.但是,在mkdirp之外,它有大量其他有用的shell操作(比如grep等......)并且它适用于windows和*nix

  • 此选项可能会在没有命令行mkdir实例(即非Linux-y主机)的node.js平台上中断,因此如果重要的话,它不可移植. (17认同)
  • 谢谢!我最终使用了exec(我已经在使用它了),它就像一个魅力.var exec = require('child_process').exec; var command ="mkdir -p'"+ newDest +"'"; var options = {}; var after = function(error,stdout,stderr){console.log('error',error); console.log('stdout',stdout); console.log('stderr',stderr); } exec(命令,选项,后); (2认同)
  • @NikaKasradze 这是一个可能的解决方案并且有效。所有解决方案都是替代方案。 (2认同)

jos*_*bui 30

使用reduce我们可以验证每个路径是否存在并在必要时创建它,这样我认为它更容易理解.编辑,感谢@Arvin,我们应该使用path.sep来获取适当的特定于平台的路径段分隔符.

const path = require('path');

// Path separators could change depending on the platform
const pathToCreate = 'path/to/dir'; 
pathToCreate
 .split(path.sep)
 .reduce((prevPath, folder) => {
   const currentPath = path.join(prevPath, folder, path.sep);
   if (!fs.existsSync(currentPath)){
     fs.mkdirSync(currentPath);
   }
   return currentPath;
 }, '');
Run Code Online (Sandbox Code Playgroud)

  • 在给出答案时,最好给出一些[解释为什么你的答案](http://stackoverflow.com/help/how-to-answer). (4认同)
  • @josebui我认为最好使用"path.sep"而不是正斜杠(/)来避免环境特殊问题. (4认同)
  • 它也很好,因为它没有依赖关系 (3认同)

Cap*_*paj 29

此功能已添加到版本10.12.0中的node.js,因此就像将选项{recursive: true}作为第二个参数传递给fs.mkdir()调用一样简单.请参阅官方文档中示例.

无需外部模块或您自己的实现.


Nel*_*alo 6

我知道这是一个老问题,但是nodejs v10.12.0现在本机支持,并且recursive设置为true。fs.mkdir

// Creates /tmp/a/apple, regardless of whether `/tmp` and /tmp/a exist.
fs.mkdir('/tmp/a/apple', { recursive: true }, (err) => {
  if (err) throw err;
});
Run Code Online (Sandbox Code Playgroud)


小智 6

现在10.12.0使用NodeJS >= ,你可以使用fs.mkdirSync(path, { recursive: true }) fs.mkdirSync