在Node.js中写入文件时创建目录


134

我一直在修改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创建目录结构吗?


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

Answers:


127

节点> 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);

节点<= 10.11.0

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


4
那就是我要去的那个……那些统计数据使我无法接受。
阿兰·穆赫兰

请注意,这fs.promises仍然是实验性的nodejs.org/dist/latest-v10.x/docs/api/…–
lasec0203

132

如果您不想使用任何其他软件包,则可以在创建文件之前调用以下函数:

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

2
基于stackoverflow.com/questions/4482686/…,应使用statSync代替existsSync
GavinR '16

1
path也是需要被需要,就像一个包fsvar path = require('path')如果你想知道。请参阅节点文档
拉斐尔·埃姆肖夫

9
fs.existsSync不是过时,只有fs.exists是。
zzzzBov

6
关于fs.existsSync函数是否已过时,存在一些困惑。起初,以我的理解,我认为是的,因此我更新了答案以反映这一点。但是现在,正如@zzzzBov指出的那样,该文档明确指出仅不建议使用fs.exists,使用fs.existsSync仍然有效。因此,我删除了之前的代码,现在的答案仅包含更简单的解决方案(使用fs.existsSync)。
Tiago PeresFrança16年

1
@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”的存在。
Tiago PeresFrança18年

43

使用node-fs-extra,您可以轻松实现。

安装它

npm install --save fs-extra

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

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

您可以通过三种方式使用它:

回调样式

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

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

使用承诺

如果您使用promises,并且希望如此,则代码如下:

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

同步版本

如果要同步版本,请使用以下代码:

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

有关完整参考,请查阅outputFile文档和所有node-fs-extra支持的方法


26

无耻的插头警报!

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


1
将直接创建文件还是仅创建目录结构?我正在寻找一种在创建文件时创建文件以及目录结构的解决方案。
Hirvesh 2012年

只是目录结构。您将首先使用mkdir / path,如果没有任何错误,则继续写入文件。给定要写入文件的完整路径,编写一个函数可以同时执行这两个操作就足够简单了-只需使用path.basename
jrajav 2012年

1
实际上,它是如此简单,我只花了2分钟就把它写完了。:)(未经测试)
jrajav 2012年

更新:经过测试和编辑,如果第一次不起作用,请重试。
jrajav 2012年

8
@Kiyura与广泛使用的mkdirp有何不同?
David Weldon,2012年

9

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

function mkdirp(filepath) {
    var dirname = path.dirname(filepath);

    if (!fs.existsSync(dirname)) {
        mkdirp(dirname);
    }

    fs.mkdirSync(filepath);
}

1
这是因为@tiago的解决方案需要文件路径。在您的情况下,abc被解释为您需要为其创建目录的文件。要同时创建abc目录,请在路径中添加一个虚拟文件,例如C:/test/abc/dummy.txt
Sphinxxx '17

使用递归:fs.promises.mkdir(path.dirname(file), {recursive: true}).then(x => fs.promises.writeFile(file, data))
Offenso

1
@Offenso是最好的解决方案,但仅适用于Node.js版本10.12及更高版本。
Nickensoul

8

我的建议是:当您只需几行代码就可以轻松做到不依赖时

这是您要尝试用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);
    });
};

1
这样的第三行会更好吗?return fs.lstatSync(dpath).isDirectory(),否则,如果isDirectory()返回false,会发生什么?
Giorgio Aresu

2
使用递归:fs.promises.mkdir(path.dirname(file), {recursive: true}).then(x => fs.promises.writeFile(file, data))
Offenso

1
@Offenso,节点8不支持
Ievgen Naida

2

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

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

它像Node.js fs方法的包装器一样工作。所以,你可以用它完全相同的方式,你会与fs.writeFilefs.writeFileSync(包括异步和同步写入)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.