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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12899061/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 16:28:44  来源:igfitidea点击:

Creating a file only if it doesn't exist in Node.js

node.js

提问by configurator

We have a buffer we'd like to write to a file. If the file already exists, we need to increment an index on it, and try again. Is there a way to create a file only if it doesn't exist, or should I just stat files until I get an error to find one that doesn't exist already?

我们有一个要写入文件的缓冲区。如果文件已经存在,我们需要在它上面增加一个索引,然后再试一次。有没有办法仅在文件不存在时创建文件,或者我应该只创建 stat 文件,直到出现错误以找到不存在的文件?

For example, I have files a_1.jpgand a_2.jpg. I'd like my method to try creating a_1.jpgand a_2.jpg, and fail, and finally successfully create a_3.jpg.

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

The ideal method would look something like this:

理想的方法如下所示:

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

or like this:

或者像这样:

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

Does anything like this exist in node's fslibrary?

节点的fs库中是否存在这样的东西?

EDIT: My question isn't if there's a separate function that checks for existence. It's this: is there a way to create a file if it doesn't exist, in a single file system call?

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

回答by polkovnikov.ph

As your intuition correctly guessed, the naive solution with a pair of exists / writeFilecalls is wrong. Asynchronous code runs in unpredictable ways. And in given case it is

正如您的直觉正确猜到的那样,带有一对exists / writeFile调用的幼稚解决方案是错误的。异步代码以不可预测的方式运行。在给定的情况下,它是

  • Is there a file a.txt? — No.
  • (File a.txtgets created by another program)
  • Write to a.txtif it's possible. — Okay.
  • 有文件a.txt吗?- 不。
  • (文件a.txt由另一个程序创建)
  • a.txt如果可能,请写信给。- 好的。

But yes, we can do that in a single call. We're working with file system so it's a good idea to read developer manual on fs. And hey, here'san interesting part.

但是,是的,我们可以在一次调用中做到这一点。我们正在使用文件系统,因此最好阅读有关fs. 嘿,这是一个有趣的部分。

'w' - Open file for writing. The file is created (if it does not exist) or truncated (if it exists).

'wx' - Like 'w' but fails if path exists.

'w' - 打开文件进行写入。该文件被创建(如果它不存在)或被截断(如果它存在)。

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

So all we have to do is just add wxto the fs.opencall. But hey, we don't like fopen-like IO. Let's read on fs.writeFilea bit more.

所以我们所要做的就是添加wxfs.open调用中。但是,嘿,我们不喜欢fopen-like IO。让我们多读fs.writeFile一点。

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

filename String

options Object

encoding String | Null default = null

flag String default = 'r'

callback Function

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

文件名字符串

选项对象

编码字符串 | 空默认值 = 空

标志字符串默认 = 'r'

回调函数

That options.flaglooks promising. So we try

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

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

And it works perfectly for a single write. I guess this code will fail in some more bizarre ways yet if you try to solve your task with it. You have an atomary "check for a_#.jpgexistence, and write there if it's empty" operation, but all the other fsstate is not locked, and a_1.jpgfile may spontaneously disappear while you're already checking a_5.jpg. Most*file systems are no ACIDdatabases, and the fact that you're able to do at least some atomic operations is miraculous. It's very likely that wxcode won't work on some platform. So for the sake of your sanity, use database, finally.

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

Some more info for the suffering

有关苦难的更多信息

Imagine we're writing something like memoize-fsthat caches results of function calls to the file system to save us some network/cpu time. Could we open the file for reading if it exists, and for writing if it doesn't, all in the single call? Let's take a funny look on those flags. After a while of mental exercises we can see that a+does what we want: if the file doesn't exist, it creates one and opens it both for reading and writing, and if the file exists it does so without clearing the file (as w+would). But now we cannot use it neither in (smth)File, nor in create(Smth)Streamfunctions. And that seems like a missing feature.

想象一下,我们正在编写类似的东西memoize-fs,将函数调用的结果缓存到文件系统,以节省我们一些网络/CPU 时间。如果文件存在,我们可以打开文件进行读取,如果不存在则进行写入,所有这些都可以在一次调用中完成吗?让我们来有趣的看看这些标志。一会儿,我们可以看到,心理练习之后a+做我们想要的东西:如果文件不存在,它会创建一个并打开它无论是阅读和写作,如果文件存在,它这样做,但不清除文件(如w+将)。但是现在我们既不能在(smth)File中也不能在create(Smth)Stream函数中使用它。这似乎是一个缺失的功能。

So feel free to file it as a feature request (or even a bug) to Node.js github, as lack of atomic asynchronous file system API is a drawback of Node. Though don't expectchanges any time soon.

因此,请随意将其作为功能请求(甚至是错误)提交给 Node.js github,因为缺乏原子异步文件系统 API 是 Node.js 的一个缺点。虽然不要指望很快会有变化。

Edit. I would like to link to articles by Linusand by Dan Luuon why exactly you don't want to do anything smart with your fscalls, because the claim was left mostly not based on anything.

编辑。我想链接到LinusDan Luu 的文章,这些文章讨论了为什么你不想对你的fs电话做任何聪明的事情,因为这个主张基本上没有任何依据。

回答by Alvaro

What about using the aoption?

使用该a选项怎么样?

According to the docs:

根据文档

'a+' - Open file for reading and appending. The file is created if it does not exist.

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

It seems to work perfectly with createWriteStream

它似乎与 createWriteStream

回答by Katie

This method is no longer recommended. fs.exists is deprecated. See comments.

不再推荐此方法。fs.exists 已弃用。看评论。

Here are some options:

以下是一些选项:

1) Have 2 "fs" calls. The first one is the "fs.exists" call, and the second is "fs.write/ read, etc"

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) Or Create an empty filefirst:

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

--- Sync:

- - 同步:

//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) Or use "touch": https://github.com/isaacs/node-touch

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

回答by Kumar Vaibhav

Todo this in a single system call you can use the fs-extranpm module. After this the file will have been created as well as the directory it is to be placed in.

要在单个系统调用中完成此操作,您可以使用fs-extranpm 模块。在此之后,将创建文件以及放置它的目录。

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

Another way is to use ensureFileSyncwhich will do the same thing but synchronous.

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

const fs = require('fs-extra');
const file = '/tmp/this/path/does/not/exist/file.txt'
fs.ensureFileSync(file)

回答by Ivan Lazarevic

You can do something like this:

你可以这样做:

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