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

我一直在摆弄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创建目录结构,如果它不退出写入文件?

237060 次浏览

无耻的插头警报!

您必须检查您想要的路径结构中的每个目录,如果不存在则手动创建它。所有这样做的工具都已经在Node的fs模块中,但你可以简单地用我的mkpath模块:https://github.com/jrajav/mkpath来完成这一切

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

指出,

  1. 在很多情况下你会使用fs.mkdirSync而不是fs.mkdir

  2. 包含后面的斜杠是无害的/没有效果。

  3. mkdirSync/mkdir没有任何伤害,如果目录已经存在,不需要检查是否存在。

Node <= 10.11.0

你可以用mkdirpfs-extra这样的包来解决这个问题。如果你不想安装一个软件包,请参阅Tiago Peres França下面的回答。

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

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

它的工作原理类似于Node.js fs方法的包装器。所以你可以像使用fs.writeFilefs.writeFileSync一样使用它(异步和同步写入)

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

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

我的建议是:当你可以用几行代码轻松完成时,尽量不要依赖依赖项

下面是你试图在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);
});
};

由于我还不能评论,我发布了一个基于@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);
}

使用node-fs-extra你可以很容易地做到这一点。

安装它

npm install --save fs-extra

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

几乎与writeFile相同(即它覆盖),除了if

.父目录不存在,已创建

你可以用四种方法来使用它。

异步/等待

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


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

使用承诺

如果你使用承诺,代码如下:

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文档和所有Node-fs-extra支持的方法

与上面的答案相同,但是使用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);
})();

下面是一个完整的解决方案,在一个函数中创建包含所有所需子文件夹的文件夹,然后写入文件。

这是一个示例,假设您正在创建一个备份文件,并且希望在函数中传递备份文件夹名称(因此变量名称)


createFile(backupFolderName, fileName, fileContent) {
const csvFileName = `${fileName}.csv`;


const completeFilePath = join(process.cwd(), 'backups', backupFolderName);


fs.mkdirSync(completeFilePath, { recursive: true });


fs.writeFileSync(join(completeFilePath, csvFileName), fileContent, function (err) {
if (err) throw err;
console.log(csvFileName + ' file saved');
})
}