仅在Node.js中不存在时创建文件

时间:2012-10-15 15:36:57

标签: node.js

我们有一个缓冲区,我们想写一个文件。如果文件已经存在,我们需要在其上增加索引,然后再试一次。有没有办法只在它不存在的情况下创建文件,或者我应该只是stat文件,直到我收到错误找到一个不存在的文件?

例如,我有文件a_1.jpga_2.jpg。我希望我的方法尝试创建a_1.jpga_2.jpg,然后失败,最后成功创建a_3.jpg

理想的方法看起来像这样:

fs.writeFile(path, data, { overwrite: false }, function (err) {
  if (err) throw err;
  console.log('It\'s saved!');
});

或者像这样:

fs.createWriteStream(path, { overwrite: false });

节点的fs库中是否存在类似的内容?

编辑:我的问题不在于是否有一个单独的函数来检查是否存在。就是这样:在单个文件系统调用中,有没有办法在不存在的情况下创建文件?

6 个答案:

答案 0 :(得分:50)

正如你的直觉正确猜测的那样,使用exists / writeFile次调用的天真解决方案是错误的。异步代码以不可预测的方式运行。在特定情况下,它是

  • 是否有文件a.txt? - 不。
  • (文件a.txt由其他程序创建)
  • 如果可能,请写入a.txt。 - 好的。

但是,我们可以通过一次通话完成。我们正在使用文件系统,因此最好阅读fs上的开发人员手册。嘿,here's是一个有趣的部分。

  

'w' - 打开文件进行写作。创建文件(如果没有   存在)或截断(如果存在)。

     

'wx' - 与'w'相似但如果路径存在则失败。

所以,我们所要做的只是将wx添加到fs.open来电。但是,嘿,我们不喜欢fopen - 就像IO一样。让我们再看一遍fs.writeFile

  

fs.readFile(filename [,options],callback)#

     

filename String

     

选项对象

     
    

编码字符串| Null default = null

         

flag String default ='r'

  
     

回调函数

options.flag看起来很有希望。所以我们试试

fs.writeFile(path, data, { flag: 'wx' }, function (err) {
    if (err) throw err;
    console.log("It's saved!");
});

它适用于单次写入。如果你尝试用它来解决你的任务,我想这些代码会以一些更离奇的方式失败。你有一个atomary“检查a_#.jpg存在,如果它是空的那么写在那里”操作,但所有其他fs状态都没有被锁定,a_1.jpg文件可能会自动消失而你'已经检查a_5.jpg了。大多数*文件系统都不是ACID数据库,而且你至少可以做一些原子操作的事实是奇迹。 wx代码很可能无法在某个平台上运行。因此,为了您的理智,使用数据库,最后

痛苦的更多信息

想象一下,我们正在编写类似memoize-fs的东西,它将函数调用的结果缓存到文件系统,以节省一些网络/ CPU时间。如果文件存在,我们可以打开文件进行读取吗?如果不存在,我们可以打开文件吗?让我们看看那些旗帜上的搞笑表情。经过一段时间的心理练习,我们可以看到a+做了我们想要的事情:如果文件不存在,它会创建一个文件并打开它进行读写,如果文件存在则不会清除该文件(如w+所示)。但是现在我们既不能在(smth)File中使用它,也不能在create(Smth)Stream函数中使用它。这似乎是一个缺失的功能。

所以请随意将其作为功能请求(甚至是bug)提交给Node.js github,因为缺少原子异步文件系统API是Node的一个缺点。虽然don't expect很快就会发生变化。

答案 1 :(得分:10)

使用a选项怎么样?

根据the docs

  

'a +' - 打开文件进行阅读和追加。如果文件不存在,则创建该文件。

它似乎与createWriteStream

完美配合

答案 2 :(得分:5)

以下是一些选项:

1) 2" fs"呼叫即可。第一个是" fs.exists "打电话,第二个是" fs.write / read等"

//checks if the file exists. 
//If it does, it just calls back.
//If it doesn't, then the file is created.
function checkForFile(fileName,callback)
{
    fs.exists(fileName, function (exists) {
        if(exists)
        {
            callback();
        }else
        {
            fs.writeFile(fileName, {flag: 'wx'}, function (err, data) 
            { 
                callback();
            })
        }
    });
}

function writeToFile()
{
    checkForFile("file.dat",function()
    {
       //It is now safe to write/read to file.dat
       fs.readFile("file.dat", function (err,data) 
       {
          //do stuff
       });
    });
}

2)或首先创建一个空文件

---同步:

//If you want to force the file to be empty then you want to use the 'w' flag:

var fd = fs.openSync(filepath, 'w');

//That will truncate the file if it exists and create it if it doesn't.

//Wrap it in an fs.closeSync call if you don't need the file descriptor it returns.

fs.closeSync(fs.openSync(filepath, 'w'));

--- ASync:

var fs = require("fs");
fs.open(path, "wx", function (err, fd) {
    // handle error
    fs.close(fd, function (err) {
        // handle error
    });
});

3)或使用" 触摸":https://github.com/isaacs/node-touch

答案 3 :(得分:3)

在单个系统调用中,您可以使用function home($request, $response) { return $this->view->render($response, 'home.twig'); }; $app->get('/sign-in', 'home'); $app->get('/login', 'home'); npm模块。 在此之后,将创建文件以及放置它的目录。

fs-extra

另一种方法是使用ensureFileSync来做同样的事情但是同步。

const fs = require('fs-extra');
const file = '/tmp/this/path/does/not/exist/file.txt'
fs.ensureFile(file, err => {
    console.log(err) // => null
});

答案 4 :(得分:1)

使用 async / await 和 Typescript 我会这样做:

import * as fs from 'fs'

async function upsertFile(name: string) {
  try {
    // try to read file
    await fs.promises.readFile(name)
  } catch (error) {
    // create empty file, because it wasn't found
    await fs.promises.writeFile(name, '')
  }
}

答案 5 :(得分:-2)

您可以这样做:

function writeFile(i){
    var i = i || 0;
    var fileName = 'a_' + i + '.jpg';
    fs.exists(fileName, function (exists) {
        if(exists){
            writeFile(++i);
        } else {
            fs.writeFile(fileName);
        }
    });
}