节点如果不存在,如何创建目录?

时间:2014-01-17 20:08:41

标签: node.js

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

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

20 个答案:

答案 0 :(得分:909)

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

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

答案 1 :(得分:161)

不,原因有多种。

  1. path模块没有exists / existsSync方法。它位于fs模块中。 (也许你刚刚在你的问题上写错了?)

  2. The docs explicitly discourage您使用exists

      

    fs.exists()是不合时宜的,只是出于历史原因而存在。几乎没有理由在你自己的代码中使用它。

         

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

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

  3. 通常,您应该避免使用* Sync方法。它们是阻塞的,这意味着当你进入磁盘时,程序中没有任何其他东西可以发生。这是一个非常昂贵的操作,它花费的时间打破了节点事件循环的核心假设。

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


    我在服务器应用程序中考虑使用* Sync方法的唯一一次是在启动时一次(并且只有一次)的操作。例如,require actually uses readFileSync来加载模块。

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


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

  4. 因此,如果我们将这些建议放在一起,我们会得到这样的结论:

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

    我们可以像这样使用它:

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

    当然,这并不能解决像

    这样的边缘情况
    • 如果文件夹在程序运行时被删除会怎样? (假设您只检查它在启动期间是否存在一次)
    • 如果文件夹已存在但权限错误会怎样?

答案 2 :(得分:38)

我找到了npm模块,就像这样的魅力。 它只需要在需要时递归mkdir,就像“mkdir -p”一样。

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

答案 3 :(得分:20)

以防任何人对单行版本感兴趣。 :)

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

答案 4 :(得分:14)

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

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

(可选择在模式中添加第二个参数。)

其他想法:

  1. 您可以使用then或等待使用原生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,添加了许多有用的东西)

答案 5 :(得分:10)

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

答案 6 :(得分:8)

mkdir方法可以递归创建路径中不存在的任何目录,而忽略存在的目录。

来自Node v10/11 docs

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

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

现在,这是一个更健壮的示例,该示例利用本机ES模块(已启用标志和.mjs扩展名),处理非root路径并说明完整路径名:

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

您可以像createDirectories('/components/widget/widget.js');一样使用它。

当然,您可能希望通过将诺言与async / await结合使用来在创建目录时以更具可读性的同步外观方式利用文件创建来获得更多的希望;但这超出了问题的范围。

答案 7 :(得分:6)

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

答案 8 :(得分:5)

使用fs-extra软件包,您可以使用a one-liner进行此操作:

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

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

答案 9 :(得分:3)

我想添加josh3736's answer的Typescript Promise重构。

它执行相同的操作且具有相同的边缘情况,它恰好使用Promises,typescript typedef并使用"使用strict"。

// https://en.wikipedia.org/wiki/File_system_permissions#Numeric_notation
const allRWEPermissions = parseInt("0777", 8);

function ensureFilePathExists(path: string, mask: number = allRWEPermissions): Promise<void> {
    return new Promise<void>(
        function(resolve: (value?: void | PromiseLike<void>) => void,
            reject: (reason?: any) => void): void{
            mkdir(path, mask, function(err: NodeJS.ErrnoException): void {
                if (err) {
                    if (err.code === "EEXIST") {
                        resolve(null); // ignore the error if the folder already exists
                    } else {
                        reject(err); // something else went wrong
                    }
                } else {
                    resolve(null); // successfully created folder
                }
            });
    });
}

答案 10 :(得分:3)

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

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

这可能对你有所帮助:)。

答案 11 :(得分:1)

这是一个递归创建目录的小函数:

const createDir = (dir) => {
  // This will create a dir given a path such as './folder/subfolder' 
  const splitPath = dir.split('/');
  splitPath.reduce((path, subPath) => {
    let currentPath;
    if(subPath != '.'){
      currentPath = path + '/' + subPath;
      if (!fs.existsSync(currentPath)){
        fs.mkdirSync(currentPath);
      }
    }
    else{
      currentPath = subPath;
    }
    return currentPath
  }, '')
}

答案 12 :(得分:1)

使用节点10 + ES6:

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

(async () => {
  const dir = path.join(__dirname, 'upload');

  try {
    await fs.promises.mkdir(dir);
  } catch (error) {
    if (error.code === 'EEXIST') {
      // Something already exists, but is it a file or directory?
      const lstat = await fs.promises.lstat(dir);

      if (!lstat.isDirectory()) {
        throw error;
      }
    } else {
      throw error;
    }
  }
})();

答案 13 :(得分:1)

如果子目录不存在,我必须创建它们。我用了这个:

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

function ensureDirectoryExists(p) {
    //console.log(ensureDirectoryExists.name, {p});
    const d = path.dirname(p);
    if (d && d !== p) {
        ensureDirectoryExists(d);
    }
    if (!fs.existsSync(d)) {
        fs.mkdirSync(d);
    }
}

答案 14 :(得分:1)

fs.exist()已弃用 。因此,我已经使用fs.stat()检查目录状态。如果目录不存在,则fs.stat()会引发错误,并显示类似“无此类文件或目录”的信息。然后,我创建了一个目录。

const fs = require('fs').promises;
    
const dir = './dir';
fs.stat(dir).catch(async (err) => {
  if (err.message.includes('no such file or directory')) {
    await fs.mkdir(dir);
  }
});

答案 15 :(得分:0)

使用async / await:

IMPERSONATE

您需要宣传const mkdirP = async (directory) => { try { return await fs.mkdirAsync(directory); } catch (error) { if (error.code != 'EEXIST') { throw e; } } };

fs

答案 16 :(得分:0)

  

ENOENT:没有这样的文件或目录,mkdir'./assets /

解决方案

// const fs = require('fs') in javascript
// import * as fs from "fs" in typescript
// import fs from "fs" in typescript

!fs.existsSync(`./assets/`) && fs.mkdirSync(`./assets/`, { recursive: true })

答案 17 :(得分:0)

您可以使用节点 File System 命令 fs.stat 检查dir是否存在,并使用 fs.mkdir 创建目录使用回调或 fs.mkdirSync 创建一个没有回调的目录,例如以下示例:

//first require fs
const fs = require('fs');

//Create directory if not exist (function)
const createDir = (path) => {
    //check if dir exist
    fs.stat(path, (err, stats) => {
        if(stats.isDirectory()){
            //do nothing
        }esle{
            //if the given path is not a directory, create a directory
            fs.mkdirSync(path);
        }
    });
};

答案 18 :(得分:0)

docs中,这是异步(递归)的方法:

const fs = require('fs');
const fsPromises = fs.promises;

fsPromises.access(dir, fs.constants.F_OK)
   .catch(async() => {
                await fs.mkdir(dir, { recursive: true }, function(err) {
                    if (err) {
                      console.log(err)
                    }
                  })
    });

答案 19 :(得分:0)

异步执行此操作的函数(根据使用同步函数的 SO 上的类似答案调整,我现在找不到)

 class Pagina3State extends State<Pagina3> {
   late final Future myFuture = getDataArray();

   @override
   Widget build(BuildContext context) {
       child: FutureBuilder(
              future: myFuture,
      )
   }
}