Saya memiliki aplikasi tempat saya mencari file teks dan jika ada perubahan pada file saya menggunakan OnChanged
eventhandler untuk menangani acara tersebut. Saya menggunakan NotifyFilters.LastWriteTime
tetapi masih acara dipecat dua kali. Ini kodenya.
public void Initialize()
{
FileSystemWatcher _fileWatcher = new FileSystemWatcher();
_fileWatcher.Path = "C:\\Folder";
_fileWatcher.NotifyFilter = NotifyFilters.LastWrite;
_fileWatcher.Filter = "Version.txt";
_fileWatcher.Changed += new FileSystemEventHandler(OnChanged);
_fileWatcher.EnableRaisingEvents = true;
}
private void OnChanged(object source, FileSystemEventArgs e)
{
.......
}
Dalam kasus saya OnChanged
disebut dua kali, ketika saya mengubah file teks version.txt
dan menyimpannya.
c#
filesystemwatcher
pengguna214707
sumber
sumber
Jawaban:
Saya takut ini adalah bug / fitur
FileSystemWatcher
kelas yang terkenal. Ini dari dokumentasi kelas:Sekarang ini sedikit teks tentang
Created
acara, tetapi hal yang sama berlaku untuk acara file lainnya juga. Dalam beberapa aplikasi Anda mungkin dapat menyiasatinya dengan menggunakanNotifyFilter
properti, tetapi pengalaman saya mengatakan bahwa kadang-kadang Anda harus melakukan beberapa penyaringan duplikat manual (hacks) juga.Beberapa waktu yang lalu saya memesan halaman dengan beberapa tips FileSystemWatcher . Anda mungkin ingin memeriksanya.
sumber
Saya telah "memperbaiki" masalah itu menggunakan strategi berikut dalam delegasi saya:
sumber
Setiap
OnChanged
peristiwa yang digandakan dariFileSystemWatcher
dapat dideteksi dan dibuang dengan memeriksaFile.GetLastWriteTime
cap waktu pada file yang dimaksud. Seperti itu:sumber
"Rename"
nama acara yang Anda minati):Observable.FromEventPattern<FileSystemEventArgs>(fileSystemWatcher, "Renamed") .Select(e => e.EventArgs) .Distinct(e => e.FullPath) .Subscribe(onNext);
DateTime
hanya memiliki resolusi milidetik, metode ini berfungsi bahkan jika Anda menggantinyaFile.GetLastWriteTime
denganDateTime.Now
. Bergantung pada situasi Anda, Anda juga dapat menggunakana.FullName
variabel global untuk mendeteksi peristiwa duplikat.Inilah solusi saya yang membantu saya menghentikan acara yang diangkat dua kali:
Di sini saya telah menetapkan
NotifyFilter
properti hanya dengan Nama file dan ukuran.watcher
adalah objek FileSystemWatcher saya. Semoga ini bisa membantu.sumber
Skenario saya adalah saya memiliki mesin virtual dengan server Linux di dalamnya. Saya mengembangkan file di host Windows. Ketika saya mengubah sesuatu di folder pada host saya ingin semua perubahan diunggah, disinkronkan ke server virtual melalui Ftp. Inilah cara saya menghilangkan peristiwa perubahan duplikat ketika saya menulis ke file (yang menandai folder yang berisi file yang akan dimodifikasi juga):
Terutama saya membuat hashtable untuk menyimpan informasi waktu menulis file. Kemudian jika hashtable memiliki filepath yang dimodifikasi dan nilainya waktu sama dengan perubahan file yang diberitahukan saat ini maka saya tahu itu adalah duplikat dari acara tersebut dan mengabaikannya.
sumber
ToString("o")
tetapi bersiaplah untuk lebih banyak kegagalan.Coba dengan kode ini:
sumber
if (let==false) { ... } else { let = false; }
? Luar biasa bagaimana ini mendapat upvotes, ini pasti hanya masalah lencana StackOverflow.Inilah pendekatan saya:
Ini adalah solusi yang saya gunakan untuk menyelesaikan masalah ini pada sebuah proyek di mana saya mengirim file sebagai lampiran dalam surat. Ini akan dengan mudah menghindari peristiwa dua kali dipecat bahkan dengan interval waktu yang lebih kecil tetapi dalam kasus saya 1000 baik-baik saja karena saya lebih bahagia dengan beberapa perubahan yang hilang daripada dengan membanjiri kotak surat dengan> 1 pesan per detik. Setidaknya itu berfungsi dengan baik jika beberapa file diubah pada waktu yang bersamaan.
Solusi lain yang saya pikirkan adalah mengganti daftar dengan file pemetaan kamus ke MD5 masing-masing, sehingga Anda tidak perlu memilih interval sewenang-wenang karena Anda tidak harus menghapus entri tetapi memperbarui nilainya, dan batalkan barang-barang Anda jika belum berubah. Ini memiliki kelemahan memiliki Kamus tumbuh dalam memori sebagai file dipantau dan makan lebih banyak dan lebih banyak memori, tetapi saya telah membaca di suatu tempat bahwa jumlah file yang dipantau tergantung pada buffer internal FSW, jadi mungkin tidak terlalu penting. Entah bagaimana waktu komputasi MD5 akan memengaruhi kinerja kode Anda, hati-hati = \
sumber
lock (_changedFiles) { if (_changedFiles.Contains(e.FullPath)) { return; } _changedFiles.Add(e.FullPath); // add this! } // do your stuff
_changedFiles
diakses dari beberapa utas. Salah satu cara untuk memperbaikinya adalah dengan menggunakanConcurrentDictionary
bukanList
. Cara lain adalah dengan menetapkan arusForm
keTimer.SynchronizingObject
properti, serta keFileSystemWatcher.SynchronizingObject
properti.Saya telah membuat repo Git dengan kelas yang diperluas
FileSystemWatcher
untuk memicu peristiwa hanya ketika salinan dilakukan. Ini membuang semua peristiwa yang diubah kecuali yang terakhir dan hanya meningkatkan itu ketika file menjadi tersedia untuk dibaca.Unduh FileSystemSafeWatcher dan tambahkan ke proyek Anda.
Kemudian gunakan seperti biasa
FileSystemWatcher
dan pantau saat kejadian dipicu.sumber
Saya tahu ini adalah masalah lama, tetapi memiliki masalah yang sama dan tidak ada solusi di atas yang melakukan trik untuk masalah yang saya hadapi. Saya telah membuat kamus yang memetakan nama file dengan LastWriteTime. Jadi jika file tidak ada dalam kamus akan melanjutkan dengan proses lain, periksa bijaksana untuk melihat kapan waktu terakhir dimodifikasi dan jika berbeda dari apa yang ada di kamus jalankan kode.
sumber
your code here
bagian ini, Anda harus menambahkan atau memperbarui dateTimeDictionary.dateTimeDictionary[e.FullPath] = System.IO.File.GetLastWriteTime(e.FullPath);
Salah satu 'peretasan' yang mungkin dilakukan adalah mencekik acara menggunakan Ekstensi Reaktif misalnya:
Dalam hal ini saya membatasi ke 50 ms, pada sistem saya yang cukup, tetapi nilai yang lebih tinggi harus lebih aman. (Dan seperti yang saya katakan, ini masih 'retas').
sumber
.Distinct(e => e.FullPath)
yang menurut saya jauh lebih intuitif untuk dihadapi. Dan Anda mendapatkan perilaku yang dipulihkan yang diharapkan dari API.Saya punya solusi yang sangat cepat dan sederhana di sini, itu bekerja untuk saya, dan tidak peduli peristiwa itu akan dipicu sekali atau dua kali atau lebih sesekali, lihatlah:
sumber
Inilah solusi baru yang bisa Anda coba. Bekerja dengan baik untuk saya. Dalam event handler untuk event yang diubah secara program, hilangkan handler dari output designer pesan jika diinginkan kemudian secara program menambahkan handler kembali. contoh:
sumber
this.fileSystemWatcher1.Changed -= this.fileSystemWatcher1_Changed;
harus melakukan hal yang benar.Alasan utama adalah waktu akses terakhir acara pertama adalah waktu saat ini (menulis file atau mengubah waktu). kemudian acara kedua adalah waktu akses terakhir asli file. Saya memecahkan kode.
sumber
Saya menghabiskan sejumlah besar waktu menggunakan FileSystemWatcher, dan beberapa pendekatan di sini tidak akan berfungsi. Saya benar-benar menyukai pendekatan penonaktifan acara, tetapi sayangnya, itu tidak berfungsi jika ada> 1 file yang dijatuhkan, file kedua akan paling banyak terlewatkan jika tidak setiap saat. Jadi saya menggunakan pendekatan berikut:
sumber
Kode ini bekerja untuk saya.
sumber
sebagian besar untuk masa depan saya :)
Saya menulis pembungkus menggunakan Rx:
Pemakaian:
sumber
Saya telah mengubah cara saya memonitor file dalam direktori. Alih-alih menggunakan FileSystemWatcher saya polling lokasi di utas lain dan kemudian melihat LastWriteTime file.
Dengan menggunakan informasi ini dan menyimpan indeks jalur file dan ini waktu penulisan terbaru saya dapat menentukan file yang telah berubah atau yang telah dibuat di lokasi tertentu. Ini menghapus saya dari keanehan FileSystemWatcher. Kelemahan utama adalah bahwa Anda memerlukan struktur data untuk menyimpan LastWriteTime dan referensi ke file, tetapi ini dapat diandalkan dan mudah diimplementasikan.
sumber
Anda dapat mencoba membukanya untuk menulis, dan jika berhasil maka Anda dapat menganggap aplikasi lain selesai dengan file tersebut.
Hanya membukanya untuk menulis tampaknya tidak meningkatkan acara yang diubah. Jadi itu harus aman.
sumber
sumber
Maaf untuk penggalian kubur, tapi saya sudah berjuang untuk masalah ini untuk sementara waktu sekarang dan akhirnya menemukan cara untuk menangani beberapa peristiwa yang dipecat ini. Saya ingin mengucapkan terima kasih kepada semua orang di utas ini karena saya telah menggunakannya dalam banyak referensi saat memerangi masalah ini.
Ini kode lengkap saya. Ini menggunakan kamus untuk melacak tanggal dan waktu penulisan file terakhir. Itu membandingkan nilai itu, dan jika itu sama, itu menekan peristiwa. Ini kemudian menetapkan nilai setelah memulai utas baru.
sumber
Jika tidak ditanyakan, sayang sekali tidak ada sampel solusi siap untuk F #. Untuk memperbaikinya di sini adalah resep saya, hanya karena saya bisa dan F # adalah bahasa .NET yang bagus.
Acara duplikat disaring menggunakan
FSharp.Control.Reactive
paket, yang hanya merupakan pembungkus F # untuk ekstensi reaktif. Semua itu dapat ditargetkan ke kerangka penuh ataunetstandard2.0
:sumber
Dalam kasus saya perlu mendapatkan baris terakhir dari file teks yang dimasukkan oleh aplikasi lain, segera setelah penyisipan dilakukan. Ini solusinya. Ketika acara pertama dinaikkan, saya menonaktifkan pengamat dari membesarkan orang lain, kemudian saya sebut timer TimeElapsedEvent karena ketika fungsi pegangan saya OnChanged disebut saya perlu ukuran file teks, tetapi ukuran pada waktu itu bukan ukuran sebenarnya, itu adalah ukuran file imediatelly sebelum dimasukkan. Jadi saya menunggu sebentar untuk melanjutkan dengan ukuran file yang tepat.
sumber
Coba ini, Ini berfungsi dengan baik
sumber
Saya ingin bereaksi hanya pada acara terakhir, untuk berjaga-jaga, juga pada perubahan file linux tampaknya file itu kosong pada panggilan pertama dan kemudian diisi lagi pada berikutnya dan tidak keberatan kehilangan waktu untuk berjaga-jaga jika OS memutuskan untuk melakukan beberapa perubahan file / atribut.
Saya menggunakan .NET async di sini untuk membantu saya melakukan threading.
sumber
Saya pikir solusi terbaik untuk mengatasi masalah ini adalah dengan menggunakan ekstensi reaktif Ketika Anda mengubah peristiwa menjadi dapat diamati, maka Anda bisa menambahkan Throttling (..) (awalnya disebut Debounce (..))
Kode contoh di sini
sumber
Saya bisa melakukan ini dengan menambahkan fungsi yang memeriksa duplikat dalam array buffer.
Kemudian lakukan tindakan setelah array belum dimodifikasi untuk waktu X menggunakan timer: - Atur ulang timer setiap kali ada sesuatu yang ditulis ke buffer - Lakukan tindakan pada centang
Ini juga menangkap tipe duplikasi lain. Jika Anda memodifikasi file di dalam folder, folder itu juga melempar acara Ubah.
sumber
Solusi ini bekerja untuk saya pada aplikasi produksi:
Lingkungan Hidup:
VB.Net Framework 4.5.2
Setel properti objek secara manual: NotifyFilter = Ukuran
Kemudian gunakan kode ini:
sumber
Coba ini!
sumber
Saya harus menggabungkan beberapa ide dari posting di atas dan menambahkan cek penguncian file agar berfungsi untuk saya:
sumber
Saya mendekati masalah buat ganda seperti ini, yang mengabaikan acara pertama:
sumber