我一直在摆弄Node.js,发现了一个小问题。我有一个脚本驻留在一个名为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创建目录结构,如果它不退出写入文件?


当前回答

IDK为什么,但是这个mkdir总是使一个额外的目录与文件名,如果文件名也包含在路径中;如。

// fileName = './tmp/username/some-random.jpg';
try {
  mkdirSync(fileName, { recursive: true })
} catch (error) {};

解决方案

可以这样解决:fileName.split('/')。Slice (0, -1).join('/')只生成到最后一个目录的目录,而不是文件名本身。

// fileName = './tmp/username/some-random.jpg';
try {
  mkdirSync(fileName.split('/').slice(0, -1).join('/'), { recursive: true })
} catch (error) {};

其他回答

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

安装它

npm install --save fs-extra

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

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

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

异步- await

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支持的方法。

无耻的插头警报!

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

IDK为什么,但是这个mkdir总是使一个额外的目录与文件名,如果文件名也包含在路径中;如。

// fileName = './tmp/username/some-random.jpg';
try {
  mkdirSync(fileName, { recursive: true })
} catch (error) {};

解决方案

可以这样解决:fileName.split('/')。Slice (0, -1).join('/')只生成到最后一个目录的目录,而不是文件名本身。

// fileName = './tmp/username/some-random.jpg';
try {
  mkdirSync(fileName.split('/').slice(0, -1).join('/'), { recursive: true })
} catch (error) {};

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

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