fs.regarder tiré deux fois quand je change le fichier regardé
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');
});
});
Sortie:
- quelques données
- Fait X 1
- quelques données
- Fait X 2
C'est ma faute d'utilisation ou ..?
11 réponses
L'api fs.watch
:
- est instable
- A connu un "comportement" en ce qui concerne les notifications répétées. Plus précisément, le Windows case étant le résultat de la conception de windows, où une seule modification de fichier peut être plusieurs appels à L'API windows
Je tiens compte de cela en faisant ce qui suit:
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
}
}
Je suggère de travailler avec chokidar
(https://github.com/paulmillr/chokidar) qui est beaucoup mieux que fs.watch
:
Commentant son README.md:
Noeud.js fs.watch
:
- ne signale pas les noms de fichiers sur OS X.
- ne signale pas du tout les événements lors de L'utilisation d'éditeurs comme Sublime sur OS X.
- signale souvent des événements deux fois.
- émet la plupart des modifications comme
rename
. - A beaucoup d'autres questions
- ne le fait pas fournir un moyen facile de regarder récursivement les arbres de fichiers.
Noeud.js fs.watchFile
:
- presque aussi mauvais à la gestion des événements.
- ne fournit pas non plus d'observation récursive.
- entraîne une utilisation élevée du processeur.
Si vous avez besoin de regarder votre fichier pour le change, alors vous pouvez consulter ma petite bibliothèque sur les changements dans les fichiers. Il vérifie le hachage du fichier sha1 entre les événements change
déclenchés.
Explication de la raison pour laquelle nous avons plusieurs événements déclenchés:
Vous pouvez remarquer dans certaines situations qu'un seul événement de création génère plusieurs événements créés qui sont gérés par votre composant. Par exemple, si vous utilisez un composant FileSystemWatcher pour surveiller la création de nouveaux fichiers dans un répertoire, et ensuite, testez-le en utilisant le bloc-notes pour créer un fichier, vous pouvez voir deux événements créés générés même si un seul fichier a été créé. En effet, le bloc-notes effectue plusieurs actions du système de fichiers pendant le processus d'écriture. Bloc-notes écrit sur le disque en lots qui créent le contenu du fichier, puis les attributs de fichier. Autres applications peuvent fonctionner de la même manière. Étant donné que FileSystemWatcher surveille les activités du système d'exploitation, tous les événements déclenchés par ces applications seront ramasser.
Le premier est change et le second est rename
Nous pouvons faire une différence par rapport à la fonction d'écoute
function(event, filename) {
}
Le Rappel de l'écouteur obtient deux arguments (event, filename). l'événement est 'rename' ou 'change' , et filename est le nom du fichier qui a déclenché l'événement.
// rm sourcefile targetfile
fs.watch( sourcefile_dir , function(event, targetfile)){
console.log( targetfile, 'is', event)
}
Comme un fichier source est renommé en targetfile, il appellera trois événements en tant que fait
null is rename // sourcefile not exist again
targetfile is rename
targetfile is change
Notez que, si vous voulez attraper tous ces trois evnet, regardez le répertoire de sourcefile
Je traite ce problème pour la première fois, donc toutes les réponses jusqu'à présent sont probablement meilleures que ma solution, mais aucune d'entre elles ne convenait à 100% à mon cas, donc j'ai trouvé quelque chose de légèrement différent - j'ai utilisé une opération XOR pour retourner un entier entre 0 et 1, gardant efficacement la trace et ignorant]}
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;
}
Je ne voulais pas utiliser une fonction liée au temps (comme la réponse de jwymanm) parce que le fichier que je regarde pourrait hypothétiquement obtenir mises à jour légitimes très fréquemment. Et je ne voulais pas utiliser une liste de fichiers surveillés comme le suggère Erik P, parce que je ne regarde qu'un seul fichier. La solution de Jan Święcki semblait exagérée, car je travaille sur des fichiers extrêmement courts et simples dans un environnement de faible puissance. Enfin, la réponse de Bernado m'a rendu un peu nerveux - elle ignorerait seulement la deuxième mise à jour si elle arrivait avant que j'aie fini de traiter la première, et je ne peux pas gérer ce genre d'incertitude. Si quelqu'un devait se trouver dans ce scénario très spécifique, il pourrait y avoir un certain mérite à l'approche que j'ai utilisée? S'il y a quelque chose qui ne va pas massivement, faites-le moi savoir / éditez cette réponse, mais jusqu'à présent, cela semble bien fonctionner?
NOTE: évidemment, cela fortement suppose que vous obtiendrez exactement 2 événements par changement réel. J'ai soigneusement testé cette hypothèse, évidemment, et appris ses limites. Jusqu'à présent, j'ai confirmé que:
- Modification d'un fichier dans L'éditeur Atom et enregistrement des déclencheurs 2 mises à jour
-
touch
déclenche 2 mises à jour - redirection de sortie via
>
(écrasement du contenu du fichier) déclenche 2 mises à jour -
ajout via
>>
parfois déclenche 1 Mise à jour!*
Je peux penser à des raisons parfaitement bonnes pour les comportements différents, mais nous n'avons pas besoin de savoir pourquoi quelque chose se passe pour le planifier - je voulais juste souligner que vous voudrez vérifier par vous-même dans votre propre environnement et dans le contexte de vos propres cas d'utilisation (duh) et ne pas faire confiance à un idiot auto-avoué sur internet. Cela étant dit, avec les précautions prises, Je n'ai pas eu d'étrangeté jusqu'à présent.
* divulgation complète, Je ne sais pas vraiment pourquoi cela se produit, mais nous avons déjà affaire à un comportement imprévisible avec la fonction watch (), alors qu'est-ce qui est un peu plus d'incertitude? Pour tous ceux qui suivent à la maison, des ajouts plus rapides à un fichier semblent l'arrêter double mise à jour mais honnêtement, je ne sais pas vraiment, et je suis à l'aise avec le comportement de cette solution dans le cas réel, il sera utilisé, qui est un fichier d'une ligne qui sera mis à jour (contenu remplacé) comme deux fois par seconde au plus rapide.
J'obtiens parfois des enregistrements multiples de L'événement de montre provoquant le déclenchement de l'événement de montre plusieurs fois. Je l'ai résolu en gardant une liste de fichiers à regarder et en évitant d'enregistrer l'événement si le fichier est déjà dans la liste:
var watchfiles = {};
function initwatch(fn, callback) {
if watchlist[fn] {
watchlist[fn] = true;
fs.watch(fn).on('change', callback);
}
}
......
Similaire/même problème. J'avais besoin de faire des choses avec des images quand elles ont été ajoutées à un répertoire. Voici comment j'ai traité le double tir:
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;
});
Il ignorera le deuxième tir jusqu'à ce que if termine ce qu'il a à voir avec le nouveau fichier.
Comme d'autres réponses dit... Cela a eu beaucoup de problèmes, mais je peux faire face à cela de cette façon:
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
}
}
});
J'espère que je peux vous aider...
Solution la plus simple:
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 () {
// ...
})
Ma solution personnalisée
Personnellement, j'aime utiliser return
pour empêcher un bloc de code à exécuter lors de la vérification de quelque chose, alors, voici ma méthode:
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);
};
N'hésitez pas à utiliser cet exemple pour simplifier votre code. Il se peut que ne soit pas meilleur que d'utiliser un module d'autres, mais cela fonctionne plutôt bien!