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

con*_*tor 54 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!');
});
Run Code Online (Sandbox Code Playgroud)

或者像这样:

fs.createWriteStream(path, { overwrite: false });
Run Code Online (Sandbox Code Playgroud)

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

编辑:我的问题是,如果有一个单独的功能检查是否存在.就是这样:在单个文件系统调用中,有没有办法在不存在的情况下创建文件?

pol*_*.ph 61

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

  • 有档案a.txt吗? - 没有.
  • (文件a.txt由另一个程序创建)
  • 写信a.txt是否可能.- 好的.

但是,是的,我们可以在一次通话中做到这一点.我们正在使用文件系统,所以阅读开发人员手册是个好主意fs.嘿,这是一个有趣的部分.

'w' - 打开文件写作.创建文件(如果它不存在)或截断(如果存在).

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

所以我们所要做的就是添加wxfs.open通话中.但是,嘿,我们不喜欢fopenIO.让我们再读fs.writeFile一下.

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

filename字符串

选项对象

编码字符串| 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!");
});
Run Code Online (Sandbox Code Playgroud)

它适用于单次写入.如果你尝试用它来解决你的任务,我想这些代码会以一些更离奇的方式失败.你有一个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的一个缺点.虽然不希望很快就会发生变化.


Alv*_*aro 16

那么使用这个a选项呢?

根据文件:

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

它似乎与之完美配合 createWriteStream


Kat*_*tie 8

以下是一些选项:

1)有2个"fs"电话.第一个是" fs.exists "调用,第二个是" fs.write/read,etc"

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

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

--- ASync:

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

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

  • **注意fs.exists已被弃用,不再推荐使用****从[节点API(https://nodejs.org/api/fs.html#fs_fs_exists_path_callback)**:_checking如果一个文件在打开之前存在它是一种反模式,使您容易受到竞争条件的影响:另一个进程可能会在调用fs.exists()和fs.open()之间删除该文件.只需打开文件并在错误处理时处理错误.fs.exists()将被弃用._ (9认同)

Kum*_*hav 5

要在单个系统调用中执行此操作,可以使用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
});
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用确保文件同步,这将执行相同的操作但同步。

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

  • 不幸的是,这似乎并没有告诉我文件是否存在或是否由操作创建的-它只是确保文件在操作后存在,所以我不知道是否应该写入文件。 (2认同)

Iva*_*vic -1

你可以这样做:

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

  • 这个答案是错误的。该文件可以在调用“fs.exists”和“fs.writeFile”之间创建。 (6认同)
  • @Steve 文件应该使用 [`wx` 权限](http://nodejs.org/api/fs.html#fs_fs_open_path_flags_mode_callback) 打开。所以调用看起来像“fs.writeFile('path', {flag: 'wx'}, function (err, data) { ... })”。 (3认同)
  • 这里需要注意的是,@ebohlman 的评论是不必要的,因为 `fs.exists` 已经是异步的,并且会重置调用堆栈。 (2认同)