【问题标题】:Node.js create folder or use existingNode.js 创建文件夹或使用现有的
【发布时间】:2012-11-21 16:19:23
【问题描述】:

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

【问题讨论】:

  • 小挑剔,但摆脱e &&。如果!e 失败,那么你知道e 是真的。

标签: javascript node.js


【解决方案1】:

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

【讨论】:

  • 这是 mkdir 目录或使用现有目录的好方法。我不明白你为什么看不到。检查错误代码是一种礼貌的好方法,而丢弃错误代码只是一种好方法。你不同意吗?
  • 我明白你的意思了。但是,我相信有很多方法可以正确地做事。谢谢。
【解决方案2】:

fs.mkdir 的 node.js 文档基本上遵循mkdir(2) 的 Linux 手册页。这表明EEXIST 如果路径存在但不是一个目录,如果你走这条路,也会被指示出来。

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

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

【讨论】:

  • mkdir 之前调用stat 可能会出现竞争条件——请记住这一点。
【解决方案3】:

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

$ npm install mkdirp

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

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

    // path exists unless there was an error

});

【讨论】:

  • 在我看来,正确的(阅读“不添加依赖项”)答案将是@Raugaral 使用fs.exists(Sync) 的答案。
  • @RicardoPedroni 正确的方法是使用模块。模块通常全心全意地尝试解决一个问题,并且经常被维护。您可以使用 npm 轻松更新它们。此外,您应该特别避免使用 fs.exists[Sync],因为它的使用意味着竞争条件。
  • @1j01 如果平台本身支持该操作,我不认为正确的方法是使用模块。这是一条通往混乱的道路。我不得不同意从技术角度来看有更好的答案。
  • @1j01 此外,使用同步操作意味着竞争条件,因为它们的使用是对它们的解决方案。
  • 为什么不使用内部节点fs功能?
【解决方案4】:

你可以用这个:

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

【讨论】:

  • -1。我不相信这行得通,如果实体根本不存在,statSync 将引发错误,从而使代码崩溃。您需要将其包装在 try/catch 块中。
  • 对不起,我错了。将“statSync”更改为“existsSync”
  • 根据nodejs.org/api/fs.html#fs_fs_mkdirsync_path_mode mkdir 的同步变体不接受回调
  • 根据nodejs.org/api/fs.html#fs_fs_existssync_pathfs.existsSync()fs.exists() 将被弃用。
  • 错了。由于回调参数不兼容,fs.exists() 已被弃用。 fs.existsSync() 方法仍然有效。
【解决方案5】:

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

节点 >=10

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

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

同步版本。

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

异步版本

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

旧节点版本

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

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

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

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

【讨论】:

  • var fs = Npm.require('fs'); var dir = process.env.PWD + '/files/users/' + this.userId + '/';试试 { fs.mkdirSync(dir); } catch (e) { if (e.code != 'EEXIST') throw e; }
  • 我试过你的代码,创建一个使用目录创建的 js 脚本,如下所示: mkdirpSync(path.join(__dirname, 'first', 'second', 'third', 'ololol', '作品'));但是得到了这个错误:$ node 1.js fs.js:747 return binding.mkdir(pathModule._makeLong(path), ^ Error: EPERM, operation not allowed 'C:\' at Error (native) at Object.fs。 mkdirSync (fs.js:747:18) 在 mkdirpSync (C:\Users\MAXIM\Desktop\test\1.js:15:8) 在 Object. (C:\Users\MAXIM\Desktop\test\ 1.js:19:1) ...你能提出什么问题吗?显然在 Windows 上使用 :)
  • EPERM 似乎是一个权限问题,所以脚本无论如何都会中断执行
  • 我认为这样会更好: var mkdirpSync = function (dirpath) { var parts = dirpath.split(path.sep); for( var i = 1; i
  • 警告:如果您的路径以 / 开头,它将不起作用
【解决方案6】:

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

fs.existsSync("directory") || fs.mkdirSync("directory");

【讨论】:

  • fs.existsSync(...) 虽然没有被弃用,所以这个答案似乎还可以。
  • 注意!不适用于“dir/foo/bar”,即缺少 mkdir -p 标志功能
  • 这也有竞争条件
【解决方案7】:

你也可以使用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

【讨论】:

    【解决方案8】:

    为每个用户创建动态名称目录...使用此代码

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

    【讨论】:

      【解决方案9】:

      这是我用来创建目录的 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.existsdeprecated,所以我使用fs.stat 来检查目录是否已经存在
      • 如果目录不存在,错误代码将为ENOENTError NO ENTry)
      • 目录本身将使用fs.mkdir 创建
      • 我更喜欢异步函数fs.mkdir,而不是它的阻塞对应函数fs.mkdirSync,并且由于包装Promise,它将保证只有在成功创建目录后才会返回目录的路径

      【讨论】:

      • 感谢您提供不涉及不必要模块的干净解决方案。它对我来说非常有效。我希望有更多这样的答案!
      【解决方案10】:

      我提出了一个没有模块的解决方案(为了可维护性,从不建议使用累积模块,尤其是对于可以用几行编写的小功能......):

      最后更新:

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

      【讨论】:

      • fs.exists() 在节点 v9 中已弃用。请改用fs.access()。 (如果文件存在则返回undefined;否则抛出错误ENOENT
      • 没有任何 npm 包,它可以工作。这是一个有价值的代码。谢谢
      • 这个更适合在现有长路径下创建文件夹;)谢谢,伙计。
      • fs.mkdirSync('my/new/folder/create', {recursive: true}) 呢?
      • 谢谢!我更新我的帖子以帮助其他人。节点 10.12.0 太新了。
      【解决方案11】:

      Raugaral's answer 但带有 -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
      

      【讨论】:

        【解决方案12】:

        正如Teemu Ikonen's answer 的新替代品一样,它非常简单易读,是使用fs-extra 包的ensureDir 方法。

        它不仅可以公然替代内置的fs 模块,而且除了fs 包的功能外,还有很多其他的功能。

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

        上面提供的是它的async 版本。它还有一个同步方法来执行此操作,形式为ensureDirSync 方法。

        【讨论】:

          【解决方案13】:

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

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

          【讨论】:

            【解决方案14】:

            @Liberateur 的 answer above 对我不起作用(节点 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');
            

            【讨论】:

              猜你喜欢
              • 2013-01-08
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-11-05
              • 1970-01-01
              相关资源
              最近更新 更多