it-swarm.com.de

fs.watch wurde zweimal ausgelöst, wenn ich die überwachte Datei ändere

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

AUSGABE:

  • daten
  • Fertig X 1
  • daten
  • Fertig X 2

Ist es mein gebrauchsfehler oder ..? 

25

Die fs.watch-API:

  1. ist instabil
  2. hat bekannte "Verhalten" in Bezug auf wiederholte Benachrichtigungen. Der Fall windows ist ein Ergebnis des Windows-Designs, bei dem eine einzelne Dateiänderung mehrere Aufrufe der Windows-API sein kann
33
Pero P.

Ich berücksichtige dies, indem ich Folgendes mache:

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
    }
}
14
jwymanm

Ich schlage vor, mit chokidar ( https://github.com/paulmillr/chokidar ) zu arbeiten, was viel besser ist als fs.watch:

Kommentieren der README.md:

Node.js fs.watch:

  • Gibt unter OS X keine Dateinamen aus.
  • Meldet überhaupt keine Ereignisse, wenn Editoren wie Sublime unter OS X verwendet werden.
  • Häufig werden Ereignisse zweimal gemeldet.
  • Gibt die meisten Änderungen als rename aus.
  • Hat viele andere Probleme
  • Bietet keine einfache Möglichkeit, Dateibäume rekursiv zu überwachen.

Node.js fs.watchFile:

  • Fast genauso schlecht im Event-Handling.
  • Auch bietet keine rekursive Beobachtung.
  • Führt zu einer hohen CPU-Auslastung.
12
Artisan72

Wenn Sie Ihre Datei auf Änderungen überprüfen müssen, können Sie meine kleine Bibliothek on-file-change auschecken. Es überprüft den Datei-sha1-Hash zwischen ausgelösten change-Ereignissen.

Erklärung, warum wir mehrere ausgelöste Ereignisse haben:

In bestimmten Situationen stellen Sie möglicherweise fest, dass ein einzelnes Erstellungsereignis mehrere erstellte Ereignisse generiert, die von Ihrer Komponente verarbeitet werden. Wenn Sie beispielsweise eine FileSystemWatcher-Komponente verwenden, um die Erstellung neuer Dateien in einem Verzeichnis zu überwachen, und dann mithilfe von Editor zum Erstellen einer Datei testen, werden möglicherweise zwei erstellte Ereignisse generiert, obwohl nur eine einzige Datei erstellt wurde. Dies liegt daran, dass Notepad während des Schreibvorgangs mehrere Dateisystemaktionen ausführt. Notepad schreibt in Batches auf die Festplatte, die den Inhalt der Datei und dann die Dateiattribute erstellt. Andere Anwendungen können auf dieselbe Weise ausgeführt werden. Da FileSystemWatcher die Betriebssystemaktivitäten überwacht, werden alle Ereignisse, die diese Anwendungen auslösen, erfasst.

Quelle

8
Jan Święcki

Ich beschäftige mich zum ersten Mal mit diesem Problem, daher sind alle bisherigen Antworten wahrscheinlich besser als meine Lösung, jedoch war keine von ihnen zu 100% für meinen Fall geeignet, sodass ich mir etwas anderes einfiel - ich habe a = verwendet XOR Operation zum Umkehren einer Ganzzahl zwischen 0 und 1, wobei effektiv jedes zweite Ereignis in der Datei verfolgt und ignoriert wird:

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

Ich wollte keine zeitbezogene Funktion verwenden (wie die Antwort von jwymanm), da die von mir betrachtete Datei möglicherweise sehr häufig legitime Aktualisierungen erhält. Und ich wollte keine Liste der beobachteten Dateien verwenden, wie Erik P vorschlägt, weil ich nur eine Datei beobachte. Die Lösung von Jan Święcki schien zu viel zu sein, da ich an extrem kurzen und einfachen Dateien in einer Umgebung mit geringem Stromverbrauch arbeite. Zuletzt machte mich Bernados Antwort etwas nervös - es würde das zweite Update nur ignorieren, wenn es eintreffen würde, bevor ich das erste bearbeitet hätte, und ich kann mit dieser Art von Unsicherheit nicht umgehen. Wenn sich jemand in diesem sehr spezifischen Szenario wiederfindet, könnte der Ansatz, den ich verwendet habe, einige Vorteile haben? Wenn irgendetwas massiv falsch ist, lass es mich bitte wissen/bearbeite diese Antwort, aber bisher scheint es gut zu funktionieren?

ANMERKUNG: Offensichtlich geht dieses stark davon aus, dass Sie genau 2 Ereignisse pro realer Änderung erhalten. Ich habe diese Annahme natürlich sorgfältig getestet und ihre Grenzen kennengelernt. Bisher habe ich folgendes bestätigt:

  • Ändern einer Datei im Atom Editor und Speichern von Triggern 2 Updates
  • touch löst 2 Aktualisierungen aus
  • Ausgabeumleitung über > (Dateiinhalt überschreiben) löst 2 Aktualisierungen aus
  • Anhängen über >> löst manchmal 1 Update aus! *

Ich kann mir durchaus gute Gründe für das unterschiedliche Verhalten vorstellen, aber wir müssen nicht wissen , warum etwas passiert, um es zu planen - ich wollte nur betonen Sie, dass Sie sich in Ihrer eigenen Umgebung und im Kontext Ihrer eigenen Anwendungsfälle (duh) selbst davon überzeugen möchten, dass Sie einem selbstbekannten Idioten im Internet nicht vertrauen. Unter Berücksichtigung der getroffenen Vorkehrungen hatte ich bisher keine Seltsamkeiten.

* Vollständige Offenlegung, ich weiß eigentlich nicht, warum dies geschieht, aber wir haben es bereits mit unvorhersehbarem Verhalten der Funktion watch () zu tun. Was ist also ein bisschen mehr Unsicherheit? Wenn jemand zu Hause mithört, dass eine Datei schneller angehängt wird, scheint dies dazu zu führen, dass sie nicht mehr doppelt aktualisiert wird. Ehrlich gesagt, ich weiß es nicht wirklich und bin mit dem Verhalten dieser Lösung im konkreten Fall zufrieden verwendet werden, das ist eine einzeilige Datei, die wie zweimal pro Sekunde am schnellsten aktualisiert (Inhalte ersetzt) ​​wird.

1
Toadfish

erstens ist ändern und das zweite ist umbenennen

wir können von der Listener-Funktion unterscheiden

function(event, filename) {

}

Der Listener-Callback erhält zwei Argumente (Ereignis, Dateiname). event ist entweder 'rename' oder 'change' und Dateiname ist der Name der Datei, die das Event ausgelöst hat.

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

da eine Quelldatei in Zieldatei umbenannt wird, werden drei Ereignisse als Tatsache bezeichnet

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

beachten Sie, wenn Sie alle drei evnet fangen möchten, achten Sie auf das Verzeichnis der Quelldatei

1
liandong

Ich bekomme manchmal mehrfache Registrierungen des Watch-Ereignisses, was dazu führt, dass das Watch-Ereignis mehrmals ausgelöst wird ... Ich löste es, indem ich eine Liste mit Überwachungsdateien führte und die Registrierung des Ereignisses vermeide, wenn die Datei bereits in der Liste enthalten ist:

 var watchfiles = {};

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

......

0
Erik P

Einfachste Lösung:

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

Wie andere Antworten sagen ... Dies hatte viele Probleme, aber ich kann damit auf folgende Weise umgehen:

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

Hoffnung kann ich dir helfen ...

0
carlitoxenlaweb

Ähnliches/gleiches Problem. Ich musste ein paar Sachen mit Bildern machen, als sie einem Verzeichnis hinzugefügt wurden. So bin ich mit dem Double Firing umgegangen:

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

Das zweite Auslösen wird ignoriert, bis es fertig ist, was mit der neuen Datei zu tun hat.

0
Bernardo SOUSA

Meine individuelle Lösung

Ich persönlich mag es, return zu verwenden, um zu verhindern, dass ein Codeblock ausgeführt wird, wenn etwas überprüft wird. Hier ist meine Methode:

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

Verwenden Sie dieses Beispiel, um Ihren Code zu vereinfachen. Es kannNICHTbesser sein, als ein Modul von anderen zu verwenden, aber es funktioniert ziemlich gut!

0
Lasse Brustad