如果目录不存在,如何使用 Node.js 创建目录?

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

How to create a directory if it doesn't exist using Node.js?

node.js

提问by Whisher

Is this the right way to create a directory if it doesn't exist. It should have full permission for the script and readable by others.

如果目录不存在,这是创建目录的正确方法吗?它应该对脚本具有完全权限并且其他人可读。

var dir = __dirname + '/upload';
if (!path.existsSync(dir)) {
    fs.mkdirSync(dir, 0744);
}

回答by chovy

var fs = require('fs');
var dir = './tmp';

if (!fs.existsSync(dir)){
    fs.mkdirSync(dir);
}

回答by josh3736

No, for multiple reasons.

不,出于多种原因。

  1. The pathmodule does not have an exists/existsSyncmethod. It is in the fsmodule. (Perhaps you just made a typo in your question?)

  2. The docs explicitly discourageyou from using exists.

    fs.exists()is an anachronism and exists only for historical reasons. There should almost never be a reason to use it in your own code.

    In particular, checking if a file exists before opening it is an anti-pattern that leaves you vulnerable to race conditions: another process may remove the file between the calls to fs.exists()and fs.open(). Just open the file and handle the error when it's not there.

    Since we're talking about a directory rather than a file, this advice implies you should just unconditionally call mkdirand ignore EEXIST.

  3. In general, You should avoid the *Syncmethods. They're blocking, which means absolutely nothing else in your program can happen while you go to the disk. This is a very expensive operation, and the time it takes breaks the core assumption of node's event loop.

    The *Syncmethods are usuallyfine in single-purpose quick scripts (those that do one thing and then exit), but should almost never be used when you're writing a server: your server will be unable to respond to anyone for the entire duration of the I/O requests. If multiple client requests require I/O operations, your server will very quickly grind to a halt.


    The only time I'd consider using *Syncmethods in a server application is in an operation that happens once(and only once), at startup. For example, requireactually uses readFileSyncto load modules.

    Even then, you still have to be careful because lots of synchronous I/O can unnecessarily slow down your server's startup time.


    Instead, you should use the asynchronous I/O methods.

  1. path模块没有exists/existsSync方法。它在fs模块中。(也许您只是在问题中打错了字?)

  2. 这些文档明确劝阻您不要使用exists.

    fs.exists()是不合时宜的,仅因历史原因而存在。几乎永远不会有理由在您自己的代码中使用它。

    特别是,在打开文件之前检查文件是否存在是一种反模式,使您容易受到竞争条件的影响:另一个进程可能会在调用fs.exists()和之间删除文件fs.open()。只需打开文件并在它不存在时处理错误。

    由于我们谈论的是目录而不是文件,因此该建议意味着您应该无条件地调用mkdir并忽略EEXIST

  3. 通常,您应该避免使用 *Sync方法。它们是阻塞的,这意味着当您访问磁盘时,您的程序中绝对不会发生任何其他事情。这是一个非常昂贵的操作,它花费的时间打破了节点事件循环的核心假设。

    *Sync方法在单一用途的快速脚本中通常很好(那些做一件事然后退出的),但在你编写服务器时几乎不应该使用:你的服务器将无法在整个持续时间内响应任何人的 I/O 请求。如果多个客户端请求需要 I/O 操作,您的服务器将很快停止。


    我考虑Sync在服务器应用程序中使用 *方法的唯一时间是在启动时发生一次(并且仅发生一次)的操作中。例如,require实际用于readFileSync加载模块。

    即便如此,您仍然必须小心,因为大量同步 I/O 会不必要地减慢服务器的启动时间。


    相反,您应该使用异步 I/O 方法。

So if we put together those pieces of advice, we get something like this:

所以如果我们把这些建议放在一起,我们会得到这样的东西:

function ensureExists(path, mask, cb) {
    if (typeof mask == 'function') { // allow the `mask` parameter to be optional
        cb = mask;
        mask = 0777;
    }
    fs.mkdir(path, mask, function(err) {
        if (err) {
            if (err.code == 'EEXIST') cb(null); // ignore the error if the folder already exists
            else cb(err); // something else went wrong
        } else cb(null); // successfully created folder
    });
}

And we can use it like this:

我们可以这样使用它:

ensureExists(__dirname + '/upload', 0744, function(err) {
    if (err) // handle folder creation error
    else // we're all good
});


Of course, this doesn't account for edge cases like

当然,这不考虑像

  • What happens if the folder gets deleted while your program is running? (assuming you only check that it exists once during startup)
  • What happens if the folder already exists but with the wrong permissions?
  • 如果在您的程序运行时文件夹被删除,会发生什么?(假设您只在启动期间检查它是否存在一次)
  • 如果文件夹已经存在但权限错误会怎样?

回答by Toni Gamez

I have found and npm module that works like a charm for this. It's simply do a recursively mkdir when needed, like a "mkdir -p ".

我找到了 npm 模块,它的作用就像一个魅力。它只是在需要时递归地执行 mkdir,例如“mkdir -p”。

https://www.npmjs.com/package/mkdirp

https://www.npmjs.com/package/mkdirp

回答by bit-less

The mkdirmethod has the ability to recursively createany directories in a path that don't exist, and ignore the ones that do.

mkdir方法能够在不存在的路径中递归创建任何目录,并忽略存在的目录。

From the Node v10/11 docs:

来自Node v10/11 文档

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

NOTE: You'll need to import the built-in fsmodule first.

注意:您需要先导入内置fs模块。

Now here's a little more robust example that leverages native ES Modules (with flag enabled and .mjs extension), handles non-root paths, and accounts for full pathnames:

现在这里有一个更强大的例子,它利用原生 ES 模块(启用标志和 .mjs 扩展名),处理非根路径,并考虑完整路径名:

import fs from 'fs';
import path from 'path';

createDirectories(pathname) {
   const __dirname = path.resolve();
   pathname = pathname.replace(/^\.*\/|\/?[^\/]+\.[a-z]+|\/$/g, ''); // Remove leading directory markers, and remove ending /file-name.extension
   fs.mkdir(path.resolve(__dirname, pathname), { recursive: true }, e => {
       if (e) {
           console.error(e);
       } else {
           console.log('Success');
       }
    });
}

You can use it like createDirectories('/components/widget/widget.js');.

你可以像createDirectories('/components/widget/widget.js');.

And of course, you'd probably want to get more fancy by using promises with async/await to leverage file creation in a more readable synchronous-looking way when the directories are created; but, that's beyond the question's scope.

当然,您可能希望通过使用带有 async/await 的 promises 来获得更多幻想,以便在创建目录时以更具可读性的同步方式利用文件创建;但是,这超出了问题的范围。

回答by LeOn - Han Li

Just in case any one interested in the one line version. :)

以防万一有人对单行版本感兴趣。:)

//or in typescript: import * as fs from 'fs';
const fs = require('fs');
!fs.existsSync(dir) && fs.mkdirSync(dir);

回答by SamGoody

You can just use mkdirand catch the error if the folder exists.
This is async (so best practice) and safe.

mkdir如果文件夹存在,您可以使用并捕获错误。
这是异步的(所以是最佳实践)和安全的。

fs.mkdir('/path', err => { 
    if (err && err.code != 'EEXIST') throw 'up'
    .. safely do your stuff here  
    })

(Optionally add a second argument with the mode.)

(可选地为模式添加第二个参数。)



Other thoughts:

其他想法:

  1. You could use then or await by using native promisify.

    const util = require('util'), fs = require('fs');
    const mkdir = util.promisify(fs.mkdir);
    var myFunc = () => { ..do something.. } 
    
    mkdir('/path')
        .then(myFunc)
        .catch(err => { if (err.code != 'EEXIST') throw err; myFunc() })
    
  2. You can make your own promise method, something like (untested):

    let mkdirAsync = (path, mode) => new Promise(
       (resolve, reject) => mkdir (path, mode, 
          err => (err && err.code !== 'EEXIST') ? reject(err) : resolve()
          )
       )
    
  3. For synchronous checking, you can use:

    fs.existsSync(path) || fs.mkdirSync(path)
    
  4. Or you can use a library, the two most popular being

    • mkdirp(just does folders)
    • fsextra(supersets fs, adds lots of useful stuff)
  1. 您可以使用 then 或 await 使用本机promisify

    const util = require('util'), fs = require('fs');
    const mkdir = util.promisify(fs.mkdir);
    var myFunc = () => { ..do something.. } 
    
    mkdir('/path')
        .then(myFunc)
        .catch(err => { if (err.code != 'EEXIST') throw err; myFunc() })
    
  2. 您可以制作自己的承诺方法,例如(未经测试):

    let mkdirAsync = (path, mode) => new Promise(
       (resolve, reject) => mkdir (path, mode, 
          err => (err && err.code !== 'EEXIST') ? reject(err) : resolve()
          )
       )
    
  3. 对于同步检查,您可以使用:

    fs.existsSync(path) || fs.mkdirSync(path)
    
  4. 或者你可以使用一个库,最流行的两个是

    • mkdirp(只做文件夹)
    • fsextra(超集 fs,添加了很多有用的东西)

回答by galki

With the fs-extrapackage you can do this with a one-liner:

使用fs-extra包,您可以使用one-liner执行此操作:

const fs = require('fs-extra');

const dir = '/tmp/this/path/does/not/exist';
fs.ensureDirSync(dir);

回答by Abdul Vajid

The best solution would be to use the npm module called node-fs-extra. It has a method called mkdirwhich creates the directory you mentioned. If you give a long directory path, it will create the parent folders automatically. The module is a super set of npm module fs, so you can use all the functions in fsalso if you add this module.

最好的解决方案是使用名为node-fs-extra的 npm 模块。它有一个方法叫做mkdir创建你提到的目录。如果您提供长目录路径,它将自动创建父文件夹。该模块是 npm 模块的超集fs,因此fs如果添加此模块,您也可以使用其中的所有功能。

回答by Ping.Goblue

var dir = 'path/to/dir';
try {
  fs.mkdirSync(dir);
} catch(e) {
  if (e.code != 'EEXIST') throw e;
}

回答by Vishnu S Babu

    var filessystem = require('fs');
    var dir = './path/subpath/';

    if (!filessystem.existsSync(dir)){
        filessystem.mkdirSync(dir);
    }else
    {
        console.log("Directory already exist");
    }

This may help you :)

这可能对你有帮助:)