web-dev-qa-db-ja.com

監視対象のファイルを変更すると、fs.watchが2回起動されました

 fs.watch( 'example.xml', function ( curr, prev ) {
   // on file change we can read the new xml
   fs.readFile( 'example.xml','utf8', function ( err, data ) {
     if ( err ) throw err;
     console.dir(data);
     console.log('Done');
   });
 });

出力:

  • 一部のデータ
  • 完了X 1
  • 一部のデータ
  • 完了X 2

それは私の使用法の誤りか..?

30

fs.watch api:

  1. is nstable
  2. 繰り返し通知に関して 既知の「動作」 があります。具体的には、 windows case はWindowsの設計の結果であり、単一のファイルの変更がWindows APIへの複数の呼び出しである可能性があります。
40
Pero P.

私は以下を行うことでこれを考慮に入れます:

var fsTimeout

fs.watch('file.js', function(e) {

    if (!fsTimeout) {
        console.log('file.js %s event', e)
        fsTimeout = setTimeout(function() { fsTimeout=null }, 5000) // give 5 seconds for multiple events
    }
}
17
jwymanm

fs.watchよりも優れているchokidarhttps://github.com/paulmillr/chokidar )を使用することをお勧めします。

README.mdへのコメント:

Node.js fs.watch

  • OS Xではファイル名を報告しません。
  • OS XでSublimeのようなエディターを使用する場合、イベントをまったく報告しません。
  • 多くの場合、イベントを2回報告します。
  • ほとんどの変更をrenameとして発行します。
  • あり 他の多くの問題
  • ファイルツリーを再帰的に監視する簡単な方法は提供しません。

Node.js fs.watchFile

  • イベント処理がほぼ同じです。
  • また、再帰的なウォッチングも提供していません。
  • CPU使用率が高くなります。
13
Artisan72

ファイルの変更を監視する必要がある場合は、私の小さなライブラリ on-file-change を確認してください。発生したchangeイベント間のファイルsha1ハッシュをチェックします。

複数の発生したイベントがある理由の説明:

特定の状況では、単一の作成イベントが、コンポーネントによって処理される複数のCreatedイベントを生成することに気付く場合があります。たとえば、FileSystemWatcherコンポーネントを使用してディレクトリ内の新しいファイルの作成を監視し、メモ帳を使用してそれをテストしてファイルを作成すると、1つのファイルしか作成されていなくても、2つのCreatedイベントが生成されることがあります。これは、メモ帳が書き込みプロセス中に複数のファイルシステムアクションを実行するためです。メモ帳は、ファイルのコンテンツを作成してからファイル属性を作成するバッチでディスクに書き込みます。他のアプリケーションも同じ方法で実行できます。 FileSystemWatcherはオペレーティングシステムのアクティビティを監視するため、これらのアプリケーションが起動するすべてのイベントが取得されます。

ソース

10
Jan Święcki

私はこの問題を初めて扱っているので、これまでのすべての回答はおそらく私の解決策よりも優れていますが、それらのどれも私のケースに100%適していなかったため、少し異なるものを思いつきました-私は= XOR 0と1の間の整数を反転する操作は、ファイルの2番目のイベントを効果的に追跡し、無視します。

var targetFile = "./watchThis.txt"; 
var flippyBit = 0; 

fs.watch(targetFile, {persistent: true}, function(event, filename) {

      if (event == 'change'){
        if (!flippyBit) {
          var data = fs.readFile(targetFile, "utf8", function(error, data) {
            gotUpdate(data);
          })
        } else {
          console.log("Doing nothing thanks to flippybit.");              
        }
        flipBit(); // call flipBit() function
      }
    });

// Whatever we want to do when we see a change
function gotUpdate(data) {
    console.log("Got some fresh data:");
    console.log(data);
    }


// Toggling this gives us the "every second update" functionality

function flipBit() {
    flippyBit = flippyBit ^ 1;
}

時間に関連する関数(jwymanmの回答など)を使用したくありませんでした。これは、監視しているファイルが仮想的に頻繁に正当な更新を取得する可能性があるためです。また、Erik Pが提案するように、監視しているファイルのリストを使用したくありませんでした。これは、1つのファイルしか監視していないためです。 JanŚwięckiのソリューションは、低電力環境で非常に短くシンプルなファイルに取り組んでいるため、やり過ぎのように思えました。最後に、ベルナドの答えは少し緊張しました。最初の処理が完了する前に2番目の更新が到着した場合にのみ無視され、そのような不確実性を処理できません。この非常に具体的なシナリオで誰かが自分を見つけたとしたら、私が使用したアプローチにはいくつかのメリットがあるかもしれませんか?それに大きな問題がある場合は、私にこの回答を知らせてください/編集してください。

注:明らかにこれstronglyは、実際の変更ごとに正確に2つのイベントを取得すると想定しています。私は明らかにこの仮定を慎重にテストし、その限界を学びました。これまでのところ、私はそれを確認しました:

  • Atomエディターでのファイルの変更とトリガーの保存2つの更新
  • touchトリガー2更新
  • >(ファイル内容の上書き)トリガーによる出力リダイレクト2更新
  • >>を介して追加すると、1つの更新がトリガーされることがあります! *

異なる動作の完全に良い理由を考えることができますが、なぜ何かが起こっているのかを知る必要はありません–私はただしたかっただけです自分の環境と自分のユースケースのコンテキストで自分自身をチェックしたい(duh)ことを強調し、インターネット上の自白の馬鹿を信用しないようにします。とは言っても、予防策を講じて、今のところ奇妙なことはありません。

*完全な開示、これがなぜ起こっているのか実際にはわかりませんが、watch()関数で予測できない動作をすでに処理しているので、もう少し不確実なことは何ですか?自宅でフォローしている人にとっては、ファイルへのより迅速な追加により、ファイルの二重更新が停止するように見えますが、正直なところ、私にはよくわかりません。実際の場合、このソリューションの動作には満足しています。これは、最速で毎秒2回のように更新される(コンテンツが置き換えられる)1行のファイルです。

1
Toadfish

私のカスタムソリューション

私は個人的にreturnを使用して、何かをチェックするときにコードのブロックが実行されるのを防ぐのが好きなので、ここに私の方法があります:

var watching = false;
fs.watch('./file.txt', () => {
    if(watching) return;
    watching = true;

    // do something

    // the timeout is to prevent the script to run twice with short functions
    // the delay can be longer to disable the function for a set time
    setTimeout(() => {
        watching = false;
    }, 100);
};

この例を使用して、コードを簡略化してください。 [〜#〜]ない[〜#〜]他のモジュールを使用するよりも良いかもしれませんが、それはかなりうまくいきます!

1
Lasse Brustad

最初は変更で、2番目は名前の変更です

リスナー関数との違いを作ることができます

function(event, filename) {

}

リスナーコールバックは2つの引数(イベント、ファイル名)を取得します。 eventは 'rename'または 'change'のいずれかで、filenameはイベントをトリガーしたファイルの名前です。

// rm sourcefile targetfile
fs.watch( sourcefile_dir , function(event, targetfile)){
    console.log( targetfile, 'is', event)
}

ソースファイルの名前がターゲットファイルに変更されると、3つのイベントが実際に呼び出されます

null is rename // sourcefile not exist again
targetfile is rename
targetfile is change

これら3つのevnetをすべてキャッチしたい場合は、sourcefileのディレクトリを確認してください。

1
liandong

ときどき、Watchイベントの登録が何度も発生し、Watchイベントが数回発生します。監視ファイルのリストを保持し、ファイルがすでにリストにある場合はイベントを登録しないことで解決しました。

 var watchfiles = {};

function initwatch(fn, callback) {
    if watchlist[fn] {
        watchlist[fn] = true;
        fs.watch(fn).on('change', callback);
    }
}

…….

0
Erik P

最も簡単な解決策:

const watch = (path, opt, fn) => {
  var lock = false
  fs.watch(path, opt, function () {
    if (!lock) {
      lock = true
      fn()
      setTimeout(() => lock = false, 1000)
    }
  })
}
watch('/path', { interval: 500 }, function () {
  // ...
})
0
Arthur Araújo

他の回答が言うように...これは多くの問題を抱えましたが、私はこのようにこれに対処することができます:

var folder = "/folder/path/";

var active = true; // flag control

fs.watch(folder, function (event, filename) {
    if(event === 'rename' && active) { //you can remove this "check" event
        active = false;

        // ... its just an example
        for (var i = 0; i < 100; i++) {
            console.log(i);
        }

        // ... other stuffs and delete the file
        if(!active){
            try {
                fs.unlinkSync(folder + filename);
            } catch(err) {
                console.log(err);
            }
            active = true
        }
    }
});

お手伝いできれば幸いです...

0
carlitoxenlaweb

私は人形遣いでファイルをダウンロードしていて、ファイルが保存されると、自動メールを送信していました。上記の問題が原因で、2つのメールを送信していることに気付きました。 process.exit()を使用してアプリケーションを停止し、pm2で自動起動することで解決しました。コードでフラグを使用しても、私は救われませんでした。

将来この問題が発生した場合は、このソリューションを使用することもできます。プログラムを終了し、監視ツールで自動的に再起動します。

0
Yunus

類似/同じ問題。ディレクトリに追加されたとき、私は画像でいくつかのことをする必要がありました。これが私が二重発砲に対処した方法です:

var fs = require('fs');
var working = false;

fs.watch('directory', function (event, filename) {
  if (filename && event == 'change' && active == false) {
    active = true;

    //do stuff to the new file added

    active = false;
});

新しいファイルの処理が完了するまで、2回目の起動は無視されます。

0
Bernardo SOUSA