Node.js 创建文件夹或使用现有的

Posted

技术标签:

【中文标题】Node.js 创建文件夹或使用现有的【英文标题】:Node.js create folder or use existing 【发布时间】: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 是真的。 【参考方案1】:

这样做的好方法是使用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功能?【参考方案2】:

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

节点 >=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 警告:如果您的路径以 / 开头,它将不起作用【参考方案3】:

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

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

【讨论】:

fs.exists 已弃用:nodejs.org/api/fs.html#fs_fs_exists_path_callback fs.existsSync(...) 虽然没有被弃用,所以这个答案似乎还可以。 注意!不适用于“dir/foo/bar”,即缺少 mkdir -p 标志功能 这也有竞争条件【参考方案4】:

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

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

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

【讨论】:

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

你可以用这个:

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_path,fs.existsSync()fs.exists() 将被弃用。 错了。由于回调参数不兼容,fs.exists() 已被弃用。 fs.existsSync() 方法仍然有效。【参考方案6】:

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

最后更新:

在 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 太新了。【参考方案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】:

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

【讨论】:

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

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

【讨论】:

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

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

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

【讨论】:

【参考方案11】:

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

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

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

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

【讨论】:

【参考方案12】:

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

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

【讨论】:

【参考方案13】:

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

【讨论】:

【参考方案14】:

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

【讨论】:

以上是关于Node.js 创建文件夹或使用现有的的主要内容,如果未能解决你的问题,请参考以下文章

npm 创建 node.js 项目

node.js+mongoose UserSchema findOrCreate

Sequelize sync() 不会创建所有的表模型

Swagger 生成 Node.JS Express 服务器代码

node.js总结

如何使用现有的json文件创建tmTheme文件?