【问题标题】:Create Directory When Writing To File In Node.js在 Node.js 中写入文件时创建目录
【发布时间】:2012-11-12 14:53:30
【问题描述】:

我一直在修补 Node.js,发现了一个小问题。我有一个脚本,它位于一个名为data 的目录中。我希望脚本将一些数据写入data 子目录中的子目录中的文件。但是我收到以下错误:

{ [Error: ENOENT, open 'D:\data\tmp\test.txt'] errno: 34, code: 'ENOENT', path: 'D:\\data\\tmp\\test.txt' }

代码如下:

var fs = require('fs');
fs.writeFile("tmp/test.txt", "Hey there!", function(err) {
    if(err) {
        console.log(err);
    } else {
        console.log("The file was saved!");
    }
}); 

如果 Node.js 不退出以写入文件,谁能帮我找出如何让 Node.js 创建目录结构?

【问题讨论】:

  • fs.promises.mkdir(path.dirname("tmp/test.txt"), {recursive: true}).then(x => fs.promises.writeFile("tmp/test.txt", "Hey there!"))

标签: javascript node.js


【解决方案1】:

使用node-fs-extra,您可以轻松做到。

安装它

npm install --save fs-extra

然后使用outputFile 方法。它的文档说:

几乎与writeFile 相同(即覆盖),除了如果 父目录不存在,已创建。

您可以通过四种方式使用它。

异步/等待

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

await fse.outputFile('tmp/test.txt', 'Hey there!');

使用承诺

如果你使用promises,代码如下:

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

fse.outputFile('tmp/test.txt', 'Hey there!')
   .then(() => {
       console.log('The file has been saved!');
   })
   .catch(err => {
       console.error(err)
   });

回调样式

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

fse.outputFile('tmp/test.txt', 'Hey there!', err => {
  if(err) {
    console.log(err);
  } else {
    console.log('The file has been saved!');
  }
})

同步版本

如果您想要同步版本,只需使用以下代码:

const fse = require('fs-extra')

fse.outputFileSync('tmp/test.txt', 'Hey there!')

如需完整参考,请查看outputFile documentation 和所有node-fs-extra supported methods

【讨论】:

    【解决方案2】:

    与上述相同的答案,但使用 async await 并可以使用!

    const fs = require('fs/promises');
    const path = require('path');
    
    async function isExists(path) {
      try {
        await fs.access(path);
        return true;
      } catch {
        return false;
      }
    };
    
    async function writeFile(filePath, data) {
      try {
        const dirname = path.dirname(filePath);
        const exist = await isExists(dirname);
        if (!exist) {
          await fs.mkdir(dirname, {recursive: true});
        }
        
        await fs.writeFile(filePath, data, 'utf8');
      } catch (err) {
        throw new Error(err);
      }
    }
    

    例子:

    (async () {
      const data = 'Hello, World!';
      await writeFile('dist/posts/hello-world.html', data);
    })();
    

    【讨论】:

    • 惊人的答案。
    【解决方案3】:

    节点 > 10.12.0

    fs.mkdir 现在接受 { 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;
    });
    

    或承诺:

    fs.promises.mkdir('/tmp/a/apple', { recursive: true }).catch(console.error);
    

    节点

    您可以使用 mkdirpfs-extra 之类的软件包解决此问题。如果您不想安装软件包,请参阅下面的 Tiago Peres França 的回答。

    【讨论】:

    • 这就是我要和我一起去的那个......那些统计数据让我心服口服。
    • 请注意 fs.promises 仍处于实验阶段 nodejs.org/dist/latest-v10.x/docs/api/…
    • 如果你因为试图创建本地目录临时文件而使用这个,你必须传入'./tmp/a/apple'
    【解决方案4】:

    如果您不想使用任何额外的包,您可以在创建文件之前调用以下函数:

    var path = require('path'),
        fs = require('fs');
    
    function ensureDirectoryExistence(filePath) {
      var dirname = path.dirname(filePath);
      if (fs.existsSync(dirname)) {
        return true;
      }
      ensureDirectoryExistence(dirname);
      fs.mkdirSync(dirname);
    }
    

    【讨论】:

    • 这应该使用statSync而不是existsSync,基于stackoverflow.com/questions/4482686/…
    • path 也是一个像fs:var path = require('path') 一样需要的包,以防有人想知道。见node documentation
    • fs.existsSync is not deprecated,只有fs.exists是。
    • 对于函数 fs.existsSync 是否已被弃用存在一些混淆。起初,根据我的理解,我认为是这样,所以我更新了答案以反映这一点。但是现在,正如@zzzzBov 所指出的,文档明确指出只有 fs.exists 已被弃用,使用 fs.existsSync 仍然有效。出于这个原因,我删除了之前的代码,现在我的答案只包含更简单的解决方案(使用 fs.existsSync)。
    • @chrismarx 想象以下路径:“/home/documents/a/b/c/myfile.txt”。 “/home/documents”存在,而它前面的所有内容都不存在。第一次调用“ensureDirectoryExistence”时,目录名是“/home/documents/a/b/c”。我现在不能调用 fs.mkdirSync(dirname) 因为“/home/documents/a/b”也不存在。要创建目录“c”,我需要首先确保“/home/documents/a/b”的存在。
    【解决方案5】:

    由于我还不能发表评论,因此我发布了基于 @tiago-peres-frança 出色解决方案的增强答案(谢谢!)。在路径中仅缺少最后一个目录的情况下,他的代码不会创建目录,例如输入是“C:/test/abc”并且“C:/test”已经存在。这是一个有效的 sn-p:

    function mkdirp(filepath) {
        var dirname = path.dirname(filepath);
    
        if (!fs.existsSync(dirname)) {
            mkdirp(dirname);
        }
    
        fs.mkdirSync(filepath);
    }
    

    【讨论】:

    • 那是因为@tiago 的解决方案需要一个 file 路径。在您的情况下,abc 被解释为您需要为其创建目录的文件。要同时创建 abc 目录,请在路径中添加一个虚拟文件,例如C:/test/abc/dummy.txt.
    • 使用递归:fs.promises.mkdir(path.dirname(file), {recursive: true}).then(x => fs.promises.writeFile(file, data))
    • @Offenso 这是最好的解决方案,但仅适用于 Node.js 10.12 及更高版本。
    【解决方案6】:

    我的建议是:只要几行代码就能轻松做到,尽量不要依赖依赖项

    以下是您想要在 14 行代码中实现的目标:

    fs.isDir = function(dpath) {
        try {
            return fs.lstatSync(dpath).isDirectory();
        } catch(e) {
            return false;
        }
    };
    fs.mkdirp = function(dirname) {
        dirname = path.normalize(dirname).split(path.sep);
        dirname.forEach((sdir,index)=>{
            var pathInQuestion = dirname.slice(0,index+1).join(path.sep);
            if((!fs.isDir(pathInQuestion)) && pathInQuestion) fs.mkdirSync(pathInQuestion);
        });
    };
    

    【讨论】:

    • 第三行这样不是更好吗? return fs.lstatSync(dpath).isDirectory(),否则如果 isDirectory() 返回 false 会怎样?
    • 使用递归:fs.promises.mkdir(path.dirname(file), {recursive: true}).then(x => fs.promises.writeFile(file, data))
    • @Offenso 它不受节点 8 的支持
    【解决方案7】:

    我刚刚发布了这个模块,因为我需要这个功能。

    https://www.npmjs.org/package/filendir

    它就像 Node.js fs 方法的包装器一样工作。因此,您可以像使用 fs.writeFilefs.writeFileSync 一样使用它(异步和同步写入)

    【讨论】:

      【解决方案8】:

      无耻的插头警报!

      您必须检查所需路径结构中的每个目录,如果不存在则手动创建它。 Node 的 fs 模块中已经提供了执行此操作的所有工具,但您可以使用我的 mkpath 模块完成所有这些操作:https://github.com/jrajav/mkpath

      【讨论】:

      • 是直接创建文件还是只创建目录结构?我正在寻找一种在创建文件时创建文件以及目录结构的解决方案。
      • 只是目录结构。您将首先获取 mkdir/path,如果没有任何错误,请继续写入您的文件。编写一个函数来同时执行这两项操作很简单,只要给出要写入的文件的完整路径 - 只需使用 path.basename 拆分文件名
      • 其实很简单,我wrote it in 2 minutes。 :)(未经测试)
      • 更新:经过测试和编辑,如果第一次不起作用,请重试。
      • @Kiyura 这与广泛使用的mkdirp有何不同?
      猜你喜欢
      • 2013-01-19
      • 2020-11-23
      • 2012-04-12
      • 1970-01-01
      • 2011-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多