96

ファイルに書き込みたいバッファがあります。ファイルが既に存在する場合は、そのファイルのインデックスをインクリメントして、再試行する必要があります。ファイルが存在しない場合にのみファイルを作成する方法はありますか?それとも、まだ存在しないファイルを見つけるためにエラーが発生するまでファイルを stat する必要がありますか?

たとえば、ファイルa_1.jpga_2.jpg. a_1.jpgメソッドでandの作成を試みa_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ライブラリに存在しますか?

編集:私の質問は、存在をチェックする別の関数があるかどうかではありません。それはこれです: 単一のファイルシステム呼び出しで、ファイルが存在しない場合にファイルを作成する方法はありますか?

4

6 に答える 6

88

あなたの直感が正しく推測したように、exists / writeFile呼び出しのペアを使用した単純なソリューションは間違っています。非同期コードは予測できない方法で実行されます。そして、与えられた場合、それは

  • ファイルはありますa.txtか?- いいえ。
  • (ファイルa.txtは別のプログラムによって作成されます)
  • a.txt可能であれば書き込みます。- わかった。

しかし、はい、1 回の呼び出しでそれを行うことができます。私たちはファイル システムを扱っているので、 の開発者マニュアルを読むことをお勧めしますfs。そしてねえ、ここに興味深い部分があります。

'w' - 書き込み用にファイルを開きます。ファイルが作成されるか (存在しない場合)、切り捨てられます (存在する場合)。

'wx' - 'w' と同様ですが、パスが存在する場合は失敗します。

したがって、あとは呼び出しに追加wxするだけです。fs.openでもまあ、私たちはfopenIO のようなものは好きではありません。fs.writeFileもう少し読み進めてみましょう。

fs.readFile(ファイル名[, オプション], コールバック)#

ファイル名 文字列

options オブジェクト

エンコーディング文字列 | Null デフォルト = null

フラグ文字列のデフォルト = 'r'

コールバック関数

それoptions.flagは有望に見えます。だから私たちは試します

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

そして、それは単一の書き込みに対して完全に機能します。このコードでタスクを解決しようとすると、このコードはさらに奇妙な方法で失敗すると思います。原子的な「存在を確認しa_#.jpg、空の場合はそこに書き込む」操作がありますが、他のすべてのfs状態はロックされておらず、a_1.jpg既に確認している間にファイルが自然に消える場合がありますa_5.jpg*ほとんどのファイル システムはACIDデータベースではなく、少なくともいくつかのアトミック操作を実行できるという事実は奇跡的です。wxコードが一部のプラットフォームで機能しない可能性が非常に高いです。したがって、あなたの正気のために、最後にデータベースを使用してください。

苦しみについてのもう少しの情報

memoize-fsネットワーク/CPU時間を節約するために、ファイルシステムへの関数呼び出しの結果をキャッシュするようなものを書いていると想像してください。ファイルが存在する場合は読み取り用に、存在しない場合は書き込み用に、すべて 1 回の呼び出しで開くことができますか? それらの旗を面白く見てみましょう。しばらく頭を働かせると、それが私たちの望むことを実行することがわかりa+ます: ファイルが存在しない場合、ファイルが存在しない場合は作成され、読み取りと書き込みの両方のために開かれます。ファイルが存在する場合は、ファイルをクリアせずにw+( )。(smth)Fileしかし今では、関数でも関数でも使用できませんcreate(Smth)Stream。そして、それは欠けている機能のようです。

アトミック非同期ファイル システム API の欠如は Node.js の欠点であるため、Node.js github への機能要求 (またはバグ) として気軽にファイルしてください。ただし、すぐに変更を期待しないでください。

編集。LinusDan Luuの記事にリンクしたいと思います。なぜあなたは自分のfs電話で賢いことをしたくないのかという理由についてです。

于 2015-08-02T22:36:24.093 に答える
11

この方法は推奨されなくなりました。fs.exists は非推奨です。コメントを参照してください。

以下にいくつかのオプションを示します。

1) 2 つの "fs" 呼び出しがあります。1 つ目は「fs.exists」呼び出しで、2 つ目は「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'));

--- 非同期:

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

3) または「touch」を使用: https://github.com/isaacs/node-touch

于 2015-03-12T17:19:22.840 に答える
6

これを単一のシステム コールで実行するには、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
});

もう 1 つの方法は、ensureFileSyncを使用することです。これは同じことを行いますが、同期します。

const fs = require('fs-extra');
const file = '/tmp/this/path/does/not/exist/file.txt'
fs.ensureFileSync(file)
于 2017-03-28T01:19:04.473 に答える
-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);
        }
    });
}
于 2012-10-15T18:36:41.030 に答える