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

Hir*_*esh 109 javascript node.js

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

{ [Error: ENOENT, open 'D:\data\tmp\test.txt'] errno: 34, code: 'ENOENT', path: 'D:\\data\\tmp\\test.txt' }
Run Code Online (Sandbox Code Playgroud)

代码如下:

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!");
    }
}); 
Run Code Online (Sandbox Code Playgroud)

任何人都可以帮我找出如果Node.js没有退出写入文件时如何创建目录结构?

Tia*_*nça 118

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

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);
}
Run Code Online (Sandbox Code Playgroud)

  • [`fs.existsSync`不被*弃用](https://nodejs.org/api/fs.html#fs_fs_existssync_path),只有`fs.exists`是. (8认同)
  • 关于函数fs.existsSync是否已被弃用,存在一些混淆.起初,根据我的理解,我认为是,所以我更新了答案以反映这一点.但是现在,正如@zzzzBov指出的那样,文档清楚地指出只有fs.exists被弃用了,fs.existsSync的使用仍然有效.出于这个原因,我删除了以前的代码,现在我的答案只包含更简单的解决方案(使用fs.existsSync). (6认同)
  • 根据http://stackoverflow.com/questions/4482686/check-synchronously-if-file-directory-exists-in-node-js/4482701#4482701,这应该使用statSync而不是existsSync。 (2认同)
  • 耶稣。使用递归:`fs.promises.mkdir(path.dirname(file),{recursive:true})。then(x => fs.promises.writeFile(file,data))` (2认同)

Dav*_*don 101

节点> 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;
});
Run Code Online (Sandbox Code Playgroud)

或承诺:

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

节点<= 10.11.0

您可以使用mkdirpfs-extra等软件包解决此问题.如果您不想安装软件包,请参阅下面的TiagoPeresFrança的答案.

  • 这就是我要去的那个......那些统计数据让我赢了. (4认同)

lif*_*foo 34

使用node-fs-extra,你可以做到.

安装它

npm install --save fs-extra
Run Code Online (Sandbox Code Playgroud)

然后使用该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!');
  }
})
Run Code Online (Sandbox Code Playgroud)

使用承诺

如果您使用promises,我希望如此,这是代码:

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

同步版本

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

fse.outputFileSync('tmp/test.txt', 'Hey there!')
Run Code Online (Sandbox Code Playgroud)

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


jra*_*jav 26

无耻的插头警报!

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

  • @Kiyura这与广泛使用的[mkdirp](https://npmjs.org/package/mkdirp)有什么不同? (8认同)

ill*_*art 18

与上面的答案相同,但是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);
  }
}
Run Code Online (Sandbox Code Playgroud)

例子:

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


小智 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);
}
Run Code Online (Sandbox Code Playgroud)


Ale*_* C. 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);
    });
};
Run Code Online (Sandbox Code Playgroud)

  • 使用递归:`fs.promises.mkdir(path.dirname(file), {recursive: true}).then(x =&gt; fs.promises.writeFile(file, data))` (2认同)