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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31645738/
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-02 19:08:56  来源:igfitidea点击:

How to create full path with node's fs.mkdirSync?

node.jsfs

提问by David Silva Smith

I'm trying to create a full path if it doesn't exist.

如果它不存在,我正在尝试创建完整路径。

The code looks like this:

代码如下所示:

var fs = require('fs');
if (!fs.existsSync(newDest)) fs.mkdirSync(newDest); 

This code works great as long as there is only one subdirectory (a newDest like 'dir1') however when there is a directory path like ('dir1/dir2') it fails with Error: ENOENT, no such file or directory

只要只有一个子目录(像“dir1”这样的 newDest),此代码就可以很好地工作,但是当存在像 (“dir1/dir2”) 这样的目录路径时,它会失败并显示 错误:ENOENT,没有这样的文件或目录

I'd like to be able to create the full path with as few lines of code as necessary.

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

I read there is a recursive option on fs and tried it like this

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

var fs = require('fs');
if (!fs.existsSync(newDest)) fs.mkdirSync(newDest,'0777', true);

I feel like it should be that simple to recursively create a directory that doesn't exist. Am I missing something or do I need to parse the path and check each directory and create it if it doesn't already exist?

我觉得递归创建一个不存在的目录应该是那么简单。我是否遗漏了什么,或者我是否需要解析路径并检查每个目录并在它不存在时创建它?

I'm pretty new to Node. Maybe I'm using an old version of FS?

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

采纳答案by bryanmac

One option is to use shelljs module

一种选择是使用shelljs 模块

npm install shelljs

npm 安装 shelljs

var shell = require('shelljs');
shell.mkdir('-p', fullPath);

From that page:

从该页面:

Available options:

p: full path (will create intermediate dirs if necessary)

可用选项:

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

As others have noted, there's other more focused modules. But, outside of mkdirp, it has tons of other useful shell operations (like which, grep etc...) and it works on windows and *nix

正如其他人所指出的,还有其他更集中的模块。但是,在 mkdirp 之外,它还有大量其他有用的 shell 操作(例如 which、grep 等...),并且可以在 windows 和 *nix 上运行

回答by Mouneer

Edit

编辑

NodeJS version 10.12.0has added a native support for both mkdirand mkdirSyncto create a directory recursively with recursive: trueoption as the following:

NodeJS 版本10.12.0添加了对两者的原生支持,mkdirmkdirSync使用recursive: true以下选项递归创建目录:

fs.mkdirSync(targetDir, { recursive: true });

And if you prefer fs Promises API, you can write

如果你愿意fs Promises API,你可以写

fs.promises.mkdir(targetDir, { recursive: true });

Original Answer

原答案

Create directories recursively if they do not exist! (Zero dependencies)

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

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

Usage

用法

// 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');

Demo

演示

Try It!

尝试一下!

Explanations

说明

  • [UPDATE]This solution handles platform-specific errors like EISDIRfor Mac and EPERMand EACCESfor Windows. Thanks to all the reporting comments by @PediT., @JohnQ, @deed02392, @robyoder and @Almenon.
  • This solution handles both relativeand absolutepaths. Thanks to @john comment.
  • In the case of relative paths, target directories will be created (resolved) in the current working directory. To Resolve them relative to the current script dir, pass {isRelativeToScript: true}.
  • Using path.sepand path.resolve(), not just /concatenation, to avoid cross-platform issues.
  • Using fs.mkdirSyncand handling the error with try/catchif thrown to handle race conditions: another process may add the file between the calls to fs.existsSync()and fs.mkdirSync()and causes an exception.
    • The other way to achieve that could be checking if a file exists then creating it, I.e, if (!fs.existsSync(curDir) fs.mkdirSync(curDir);. But this is an anti-pattern that leaves the code vulnerable to race conditions. Thanks to @GershomMaes comment about the directory existence check.
  • Requires Node v6and newer to support destructuring. (If you have problems implementing this solution with old Node versions, just leave me a comment)
  • [更新]该解决方案把手平台特有的错误,如EISDIRMac和EPERMEACCES用于Windows。感谢@PediT.、@JohnQ、@deed02392、@robyoder 和@Almenon 的所有报告评论。
  • 此解决方案处理相对路径和绝对路径。感谢@john 评论。
  • 在相对路径的情况下,将在当前工作目录中创建(解析)目标目录。要相对于当前脚本目录解析它们,请传递{isRelativeToScript: true}.
  • 使用path.sepand path.resolve(),而不仅仅是/串联,以避免跨平台问题。
  • 使用fs.mkdirSync和处理错误try/catchif 来处理竞争条件:另一个进程可能会在对fs.existsSync()和的调用之间添加文件fs.mkdirSync()并导致异常。
    • 实现这一目标的另一种方法是检查文件是否存在,然后创建它,即if (!fs.existsSync(curDir) fs.mkdirSync(curDir);. 但这是一种反模式,使代码容易受到竞争条件的影响。感谢@GershomMaes 关于目录存在检查的评论。
  • 需要Node v6和更新版本来支持解构。(如果您在使用旧 Node 版本实施此解决方案时遇到问题,请给我留言)

回答by cshotton

A more robust answer is to use use mkdirp.

更可靠的答案是使用 use mkdirp

var mkdirp = require('mkdirp');

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

Then proceed to write the file into the full path with:

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

fs.writeFile ('/path/to/dir/file.dat'....

回答by Deejers

fs-extra adds file system methods that aren't included in the native fs module. It is a drop in replacement for fs.

fs-extra 添加了未包含在本机 fs 模块中的文件系统方法。它是 fs 的替代品。

Install fs-extra

安装 fs-extra

$ npm install --save fs-extra

$ npm install --save fs-extra

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

There are sync and async options.

有同步和异步选项。

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

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

回答by josebui

Using reduce we can verify if each path exists and create it if necessary, also this way I think it is easier to follow. Edited, thanks @Arvin, we should use path.sep to get the proper platform-specific path segment separator.

使用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;
 }, '');

回答by Capaj

This feature has been added to node.js in version 10.12.0, so it's as easy as passing an option {recursive: true}as second argument to the fs.mkdir()call. See the example in the official docs.

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

No need for external modules or your own implementation.

不需要外部模块或您自己的实现。

回答by Nelson Owalo

i know this is an old question, but nodejs v10.12.0 now supports this natively with the recursiveoption set to true. fs.mkdir

我知道这是一个老问题,但 nodejs v10.12.0 现在支持这个,recursive选项设置为 true。文件目录

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

回答by William Penagos

Now with NodeJS >= 10.12.0, you can use fs.mkdirSync(path, { recursive: true })fs.mkdirSync

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

回答by Andrey Imshenik

Example for Windows (no extra dependencies and error handling)

Windows 示例(没有额外的依赖项和错误处理)

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

let dir = "C:\temp\dir1\dir2\dir3";

function createDirRecursively(dir) {
    if (!fs.existsSync(dir)) {        
        createDirRecursively(path.join(dir, ".."));
        fs.mkdirSync(dir);
    }
}

createDirRecursively(dir); //creates dir1\dir2\dir3 in C:\temp

回答by hypeofpipe

You can use the next function

您可以使用下一个功能

const recursiveUpload = (path: string) => { const paths = path.split("/")

const recursiveUpload = (path: string) => { const paths = path.split("/")

const fullPath = paths.reduce((accumulator, current) => {
  fs.mkdirSync(accumulator)
  return `${accumulator}/${current}`
  })

  fs.mkdirSync(fullPath)

  return fullPath
}

So what it does:

那么它的作用是:

  1. Create pathsvariable, where it stores every path by itself as an element of the array.
  2. Adds "/" at the end of each element in the array.
  3. Makes for the cycle:
    1. Creates a directory from the concatenation of array elements which indexes are from 0 to current iteration. Basically, it is recursive.
  1. 创建paths变量,它将每个路径作为数组元素单独存储。
  2. 在数组中每个元素的末尾添加“/”。
  3. 使循环:
    1. 从索引从 0 到当前迭代的数组元素的串联创建一个目录。基本上,它是递归的。

Hope that helps!

希望有帮助!

By the way, in Node v10.12.0 you can use recursive path creation by giving it as the additional argument.

顺便说一句,在 Node v10.12.0 中,您可以通过将其作为附加参数来使用递归路径创建。

fs.mkdir('/tmp/a/apple', { recursive: true }, (err) => { if (err) throw err; });

fs.mkdir('/tmp/a/apple', { recursive: true }, (err) => { if (err) throw err; });

https://nodejs.org/api/fs.html#fs_fs_mkdirsync_path_options

https://nodejs.org/api/fs.html#fs_fs_mkdirsync_path_options