简体   繁体   English

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

[英]Create Directory When Writing To File In Node.js

I've been tinkering with Node.js and found a little problem.一直在鼓捣Node.js,发现了一点问题。 I've got a script which resides in a directory called data .我有一个脚本驻留在名为data的目录中。 I want the script to write some data to a file in a subdirectory within the data subdirectory.我希望脚本将一些数据写入data子目录中子目录中的文件。 However I am getting the following error:但是我收到以下错误:

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

The code is as follows:代码如下:

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

Can anybody help me in finding out how to make Node.js create the directory structure if it does not exits for writing to a file?如果 Node.js 不退出写入文件,谁能帮我找出如何创建目录结构?

Node > 10.12.0节点 > 10.12.0

fs.mkdir now accepts a { recursive: true } option like so: 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;
});

or with a promise:或承诺:

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

Node <= 10.11.0节点 <= 10.11.0

You can solve this with a package like mkdirp or fs-extra .您可以使用mkdirpfs-extra 之类的包来解决此问题。 If you don't want to install a package, please see Tiago Peres França's answer below.如果您不想安装软件包,请参阅下面的 Tiago Peres França 的回答。

If you don't want to use any additional package, you can call the following function before creating your file:如果您不想使用任何额外的包,您可以在创建文件之前调用以下函数:

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

With node-fs-extra you can do it easily.使用node-fs-extra,您可以轻松完成。

Install it安装它

npm install --save fs-extra

Then use the outputFile method.然后使用outputFile方法。 Its documentation says:它的文档说:

Almost the same as writeFile (ie it overwrites), except that if the parent directory does not exist, it's created.几乎与 writeFile 相同(即覆盖),除了如果父目录不存在,则创建它。

You can use it in four ways:您可以通过四种方式使用它:

Async/await异步/等待

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

Using Promises使用承诺

If you use promises , this is the code:如果您使用promises ,这是代码:

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

Callback style回调样式

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

Sync version同步版本

If you want a sync version, just use this code:如果您想要同步版本,只需使用以下代码:

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

For a complete reference, check the outputFile documentation and all node-fs-extra supported methods .如需完整参考,请查看outputFile文档和所有node-fs-extra 支持的方法

Shameless plug alert!无耻的插头警报!

You will have to check for each directory in the path structure you want and create it manually if it doesn't exist.您必须检查所需路径结构中的每个目录,如果它不存在,则手动创建它。 All the tools to do so are already there in Node's fs module, but you can do all of that simply with my mkpath module: https://github.com/jrajav/mkpath Node 的 fs 模块中已经提供了所有这样做的工具,但您只需使用我的 mkpath 模块即可完成所有这些操作: https : //github.com/jrajav/mkpath

Since I cannot comment yet, I'm posting an enhanced answer based on @tiago-peres-frança fantastic solution (thanks!).由于我还不能发表评论,我发布了一个基于@tiago-peres-frança 很棒的解决方案的增强答案(谢谢!)。 His code does not make directory in a case where only the last directory is missing in the path, eg the input is "C:/test/abc" and "C:/test" already exists.在路径中只缺少最后一个目录的情况下,他的代码不会创建目录,例如输入是“C:/test/abc”并且“C:/test”已经存在。 Here is a snippet that works:这是一个有效的片段:

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

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

    fs.mkdirSync(filepath);
}

My advise is: try not to rely on dependencies when you can easily do it with few lines of codes我的建议是:当你可以用几行代码轻松做到时,尽量不要依赖依赖项

Here's what you're trying to achieve in 14 lines of code:这是您试图在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);
    });
};

I just published this module because I needed this functionality.我刚刚发布了这个模块,因为我需要这个功能。

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

It works like a wrapper around Node.js fs methods.它的工作原理类似于 Node.js fs 方法的包装器。 So you can use it exactly the same way you would with fs.writeFile and fs.writeFileSync (both async and synchronous writes)所以你可以像使用fs.writeFilefs.writeFileSync一样使用它(异步和同步写入)

Same answer as above, but with async await and ready to use!与上面相同的答案,但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);
  }
}

Example:例子:

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

I've been tinkering with Node.js and found a little problem.我一直在修改Node.js,发现一个小问题。 I've got a script which resides in a directory called data .我有一个脚本,驻留在名为data的目录中。 I want the script to write some data to a file in a subdirectory within the data subdirectory.我希望脚本写一些数据到一个文件中的子目录data子目录。 However I am getting the following error:但是我收到以下错误:

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

The code is as follows:代码如下:

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

Can anybody help me in finding out how to make Node.js create the directory structure if it does not exits for writing to a file?如果没有退出写入文件的文件,有人可以帮我找出如何使Node.js创建目录结构的方法吗?

Here is a complete solution to create the folder with all the needed subfolders, and then writing the file, all in one function.这是一个完整的解决方案,用于创建包含所有需要的子文件夹的文件夹,然后写入文件,所有这些都在一个 function 中完成。

This is an example assuming you are creating a backup file and you want to pass the backup folder name in the function (hence the name of the variables)这是一个示例,假设您正在创建一个备份文件并且您想要在 function 中传递备份文件夹名称(因此是变量的名称)


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

IDK why, but this mkdir always make an extra directory with the file name if also the filename is included in the path; IDK 为什么,但是如果文件名也包含在路径中,这个 mkdir 总是用文件名创建一个额外的目录; eg例如

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

在此处输入图像描述

Solution解决方案

It can be solved this way: fileName.split('/').slice(0, -1).join('/') which only make directories up to the last dir, not the filename itself.可以这样解决: fileName.split('/').slice(0, -1).join('/')只创建目录到最后一个目录,而不是文件名本身。

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

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM