Ответ 1
fs.watch
api:
- неустойчивый
- имеет известное "поведение" в отношении повторных уведомлений. В частности, случай Windows является результатом дизайна Windows, где одна модификация файла может быть множественным вызовом в API Windows
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
Это моя ошибка использования или...?
fs.watch
api:
Я учитываю это, выполняя следующие действия:
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
}
}
Я предлагаю работать с chokidar
(https://github.com/paulmillr/chokidar), который намного лучше, чем fs.watch
:
Комментарий к README.md:
Node.js fs.watch
:
rename
. Node.js fs.watchFile
:
Если вам нужно посмотреть файл на предмет изменений, вы можете проверить мою небольшую библиотеку on-file-change. Он проверяет хэш файла sha1 между запущенными событиями change
.
Объяснение того, почему мы имеем несколько запущенных событий:
В некоторых случаях вы можете заметить, что одно событие создания генерирует несколько созданных событий, которые обрабатываются вашим компонентом. Например, если вы используете компонент FileSystemWatcher для отслеживания создания новых файлов в каталоге, а затем протестируйте его, используя Notepad для создания файла, вы можете увидеть два созданных события, даже если был создан только один файл. Это связано с тем, что в процессе записи Notepad выполняет несколько действий файловой системы. Блокнот записывает на диск партиями, которые создают содержимое файла, а затем атрибуты файла. Другие приложения могут работать одинаково. Поскольку FileSystemWatcher контролирует действия операционной системы, все события, которые срабатывают эти приложения, будут подняты.
сначала это изменение, а второе - переименование
мы можем отличить функцию слушателя
function(event, filename) {
}
Обратный вызов прослушивателя получает два аргумента (событие, имя файла). событие - либо "переименовать", либо "изменить", а имя файла - это имя файла, вызвавшего событие.
// rm sourcefile targetfile
fs.watch( sourcefile_dir , function(event, targetfile)){
console.log( targetfile, 'is', event)
}
в качестве исходного файла переименовывается в качестве целевого файла, он будет вызывать три события как факт
null is rename // sourcefile not exist again
targetfile is rename
targetfile is change
обратите внимание, что если вы хотите поймать все эти три evnet, посмотрите каталог исходного файла
Я имею дело с этой проблемой в первый раз, поэтому все ответы до сих пор, вероятно, лучше моего решения, однако ни один из них не был на 100% подходящим для моего случая, поэтому я придумал что-то немного другое - я использовал операцию XOR для перевода целого числа от 0 до 1, эффективно отслеживая и игнорируя каждое второе событие в файле:
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 answer), потому что файл, который я просматриваю, может гипотетически получать законные обновления очень часто. И я не хотел использовать список просмотренных файлов, таких как Erik P, потому что я смотрю только один файл. Решение Яна Święcki показалось излишним, поскольку я работаю над чрезвычайно короткими и простыми файлами в среде с низким энергопотреблением. Наконец, ответ Бернадо заставил меня немного нервничать - он проигнорировал бы второе обновление, только если он прибыл, прежде чем я закончил обработку первого, и я не могу справиться с такой неопределенностью. Если кто-то окажется в этом конкретном сценарии, может быть какая-то заслуга в подходе, который я использовал? Если что-нибудь в этом роде не так, пожалуйста, дайте мне знать/отредактировать этот ответ, но пока это работает хорошо?
ПРИМЕЧАНИЕ. Очевидно, это сильно предполагает, что вы получите ровно 2 события за реальные изменения. Очевидно, я тщательно проверил это предположение и узнал его ограничения. До сих пор я подтверждал, что:
touch
триггеры 2 обновления>
(переписывание содержимого файла) триггеры 2 обновления>>
иногда запускает 1 обновление! *Я могу придумать совершенно веские причины для разных поведений, но нам не нужно знать, почему что-то происходит для планирования - я просто хотел подчеркнуть, что вы захотите проверить себя в своей собственной среде и в контексте ваших собственных случаев использования (duh) и не доверять самопознанным идиотом в Интернете. Сказанное, с принятыми предосторожностями, у меня пока не было странности.
* Полное раскрытие информации, я действительно не знаю, почему это происходит, но мы уже имеем дело с непредсказуемым поведением с функцией watch(), так что еще немного неопределенности? Для тех, кто следует за домом, более быстрое добавление к файлу, похоже, заставляет его прекратить двойное обновление, но, честно говоря, я действительно не знаю, и мне нравится поведение этого решения в том случае, если оно будет, который является однострочным файлом, который будет обновляться (содержимое заменяется), как и два раза в секунду.
Я иногда получаю многократные регистрации события Watch, вызывающие событие Watch в несколько раз. Я решил это, сохранив список наблюдаемых файлов и не регистрируя событие, если файл allready находится в списке:
var watchfiles = {};
function initwatch(fn, callback) {
if watchlist[fn] {
watchlist[fn] = true;
fs.watch(fn).on('change', callback);
}
}
......
Аналогичная проблема. Мне нужно было сделать некоторые вещи с изображениями, когда они были добавлены в каталог. Здесь, как я имел дело с двойным стрельбой:
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;
});
Он проигнорирует вторую стрельбу, пока не закончит то, что он должен делать с новым файлом.
Как и другие ответы, говорит... У этого много проблем, но я могу справиться с этим следующим образом:
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
}
}
});
Надеюсь, что смогу помочь тебе...
Самое простое решение:
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 () {
// ...
})
Мне лично нравится использовать 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);
};
Не стесняйтесь использовать этот пример для упрощения кода. Он может НЕ быть лучше, чем использовать модуль у других, но он работает очень хорошо!