Eu tenho um aplicativo em que estou procurando um arquivo de texto e, se houver alguma alteração feita no arquivo, estou usando o OnChanged
manipulador de eventos para manipular o evento. Estou usando o NotifyFilters.LastWriteTime
mas ainda assim o evento está sendo disparado duas vezes. Aqui está o código.
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)
{
.......
}
No meu caso, OnChanged
é chamado duas vezes, quando altero o arquivo de texto version.txt
e o salvo.
c#
filesystemwatcher
user214707
fonte
fonte
Respostas:
Receio que este seja um bug / recurso bem conhecido da
FileSystemWatcher
classe. Isto é da documentação da classe:Agora, esse trecho de texto é sobre o
Created
evento, mas o mesmo se aplica a outros eventos de arquivo. Em alguns aplicativos, você pode contornar isso usando oNotifyFilter
propriedade, mas minha experiência diz que, às vezes, é necessário fazer algumas filtragem duplicada manual (hacks).Há um tempo atrás, marquei uma página com algumas dicas do FileSystemWatcher . Você pode querer dar uma olhada.
fonte
Eu "corrigi" esse problema usando a seguinte estratégia em meu delegado:
fonte
Qualquer
OnChanged
evento duplicado doFileSystemWatcher
pode ser detectado e descartado, verificando oFile.GetLastWriteTime
carimbo de data e hora no arquivo em questão. Igual a:fonte
"Rename"
para o nome do evento em que você está interessado):Observable.FromEventPattern<FileSystemEventArgs>(fileSystemWatcher, "Renamed") .Select(e => e.EventArgs) .Distinct(e => e.FullPath) .Subscribe(onNext);
DateTime
apenas possui resolução de milissegundos, esse método funciona mesmo se você substituirFile.GetLastWriteTime
porDateTime.Now
. Dependendo da sua situação, você também pode usar aa.FullName
variável global em para detectar eventos duplicados.Aqui está minha solução que me ajudou a impedir que o evento fosse gerado duas vezes:
Aqui eu configurei a
NotifyFilter
propriedade apenas com o nome do arquivo e o tamanho.watcher
é o meu objeto do FileSystemWatcher. Espero que isso ajude.fonte
Meu cenário é que eu tenho uma máquina virtual com um servidor Linux. Estou desenvolvendo arquivos no host do Windows. Quando altero algo em uma pasta no host, desejo que todas as alterações sejam carregadas, sincronizadas no servidor virtual via FTP. É assim que elimino o evento de alteração duplicado quando escrevo em um arquivo (que sinaliza a pasta que contém o arquivo a ser modificado também):
Principalmente, crio uma hashtable para armazenar informações de tempo de gravação de arquivos. Então, se a hashtable tiver o caminho do arquivo modificado e seu valor de tempo for o mesmo que a alteração do arquivo notificado atualmente, sei que é a duplicata do evento e a ignoro.
fonte
ToString("o")
mas esteja preparado para mais falhas.Tente com este código:
fonte
if (let==false) { ... } else { let = false; }
? Incrível como isso foi votado, isso deve ser apenas uma questão de emblemas StackOverflow.Aqui está a minha abordagem:
Esta é a solução que usei para resolver esse problema em um projeto para o qual estava enviando o arquivo como anexo em um email. Ele evitará facilmente o evento acionado duas vezes, mesmo com um intervalo menor de timer, mas no meu caso, 1000 estava bem, pois eu estava mais feliz com poucas alterações perdidas do que com inundar a caixa de correio com> 1 mensagem por segundo. Pelo menos, funciona muito bem no caso de vários arquivos serem alterados ao mesmo tempo.
Outra solução em que pensei seria substituir a lista por um arquivo de mapeamento de dicionário para o respectivo MD5, para que você não precisasse escolher um intervalo arbitrário, pois não precisaria excluir a entrada, mas atualizar seu valor, e cancele suas coisas se não tiver mudado. Ele tem a desvantagem de ter um Dicionário crescendo na memória à medida que os arquivos são monitorados e consumindo cada vez mais memória, mas li em algum lugar que a quantidade de arquivos monitorados depende do buffer interno do FSW, talvez não seja tão crítico. Não sei como o tempo de computação MD5 afetaria o desempenho do seu código, cuidado = \
fonte
lock (_changedFiles) { if (_changedFiles.Contains(e.FullPath)) { return; } _changedFiles.Add(e.FullPath); // add this! } // do your stuff
_changedFiles
é acessado a partir de vários threads. Uma maneira de corrigi-lo é usar um emConcurrentDictionary
vez deList
. Outra maneira é atribuir a correnteForm
àTimer.SynchronizingObject
propriedade, bem como àFileSystemWatcher.SynchronizingObject
propriedade.Eu criei um repositório Git com uma classe que se estende
FileSystemWatcher
para acionar os eventos somente quando a cópia é feita. Ele descarta todos os eventos alterados, exceto o último e o gera somente quando o arquivo fica disponível para leitura.Baixar FileSystemSafeWatcher e adicione-o ao seu projeto.
Em seguida, use-o normalmente
FileSystemWatcher
e monitore quando os eventos forem acionados.fonte
Sei que esse é um problema antigo, mas tinha o mesmo problema e nenhuma das soluções acima realmente resolveu o problema que estava enfrentando. Eu criei um dicionário que mapeia o nome do arquivo com o LastWriteTime. Portanto, se o arquivo não estiver no dicionário, prosseguirá com o processo de outra forma, para verificar quando foi a última vez modificada e se é diferente do que está no dicionário, execute o código.
fonte
your code here
seção, você deve adicionar ou atualizar o dateTimeDictionary.dateTimeDictionary[e.FullPath] = System.IO.File.GetLastWriteTime(e.FullPath);
Um possível "hack" seria limitar os eventos usando as Extensões reativas, por exemplo:
Nesse caso, estou acelerando para 50ms, no meu sistema, o suficiente, mas valores mais altos devem ser mais seguros. (E como eu disse, ainda é um 'hack').
fonte
.Distinct(e => e.FullPath)
que eu acho muito mais intuitivo para lidar. E você recuperou o comportamento esperado da API.Eu tenho uma solução muito rápida e simples aqui, funciona para mim e, independentemente do evento ser acionado uma ou duas vezes ou mais vezes, ocasionalmente, confira:
fonte
Aqui está uma nova solução que você pode tentar. Funciona bem para mim. No manipulador de eventos do evento alterado, remova programaticamente o manipulador da saída do designer, se desejado, e adicione programaticamente o manipulador novamente. exemplo:
fonte
this.fileSystemWatcher1.Changed -= this.fileSystemWatcher1_Changed;
deve fazer a coisa certa.O principal motivo foi o último horário de acesso do primeiro evento foi o horário atual (gravação do arquivo ou horário alterado). o segundo evento era a última hora de acesso original do arquivo. Eu resolvo sob código.
fonte
Passei uma quantidade significativa de tempo usando o FileSystemWatcher, e algumas das abordagens aqui não funcionarão. Gostei muito da abordagem de eventos incapacitantes, mas, infelizmente, não funciona se houver> 1 arquivo sendo descartado; o segundo arquivo será perdido mais, se não o tempo todo. Então, eu uso a seguinte abordagem:
fonte
Este código funcionou para mim.
fonte
principalmente para o futuro me :)
Eu escrevi um wrapper usando Rx:
Uso:
fonte
Mudei a maneira como monitore arquivos em diretórios. Em vez de usar o FileSystemWatcher, pesquiso locais em outro encadeamento e, em seguida, observe o LastWriteTime do arquivo.
Usando essas informações e mantendo um índice de um caminho de arquivo e a última hora de gravação, posso determinar os arquivos que foram alterados ou que foram criados em um local específico. Isso me remove das estranhezas do FileSystemWatcher. A principal desvantagem é que você precisa de uma estrutura de dados para armazenar o LastWriteTime e a referência ao arquivo, mas é confiável e fácil de implementar.
fonte
Você pode tentar abri-lo para gravação e, se for bem-sucedido, poderá assumir que o outro aplicativo é feito com o arquivo.
Apenas abri-lo para gravação parece não aumentar o evento alterado. Portanto, deve ser seguro.
fonte
fonte
Sinto muito pela escavação grave, mas estou lutando contra esse problema há um tempo e finalmente encontrei uma maneira de lidar com esses vários eventos disparados. Gostaria de agradecer a todos neste tópico, pois o usei em muitas referências ao combater esse problema.
Aqui está o meu código completo. Ele usa um dicionário para rastrear a data e hora da última gravação do arquivo. Ele compara esse valor e, se for o mesmo, suprime os eventos. Em seguida, define o valor após o início do novo thread.
fonte
Caso não seja solicitado, é uma pena que não haja amostras de soluções prontas para F #. Para corrigir isso aqui está a minha receita, apenas porque eu posso e o F # é uma maravilhosa linguagem .NET.
Eventos duplicados são filtrados usando o
FSharp.Control.Reactive
pacote, que é apenas um wrapper F # para extensões reativas. Tudo isso pode ser direcionado para a estrutura completa ounetstandard2.0
:fonte
No meu caso, preciso obter a última linha de um arquivo de texto que é inserido por outro aplicativo, assim que a inserção for concluída. Aqui está a minha solução. Quando o primeiro evento é disparado, desabilito o observador de gerar outros e chamo o timer TimeElapsedEvent porque, quando minha função de identificador OnChanged é chamada, preciso do tamanho do arquivo de texto, mas o tamanho naquele momento não é o tamanho real, é o tamanho do arquivo imediatamente antes da inserção. Então, espero um pouco para prosseguir com o tamanho certo do arquivo.
fonte
Tente isso, está funcionando bem
fonte
Eu queria reagir apenas no último evento, apenas no caso, também em uma alteração de arquivo linux, parecia que o arquivo estava vazio na primeira chamada e depois preenchido novamente na próxima e não me importei em perder algum tempo, apenas no caso do sistema operacional. decidiu fazer alguma alteração no arquivo / atributo.
Estou usando o .NET assíncrono aqui para me ajudar a realizar a segmentação.
fonte
Eu acho que a melhor solução para resolver o problema é usar extensões reativas. Quando você transforma um evento em observável, basta adicionar Throttling (..) (originalmente chamado Debounce (..))
Exemplo de código aqui
fonte
Consegui fazer isso adicionando uma função que verifica duplicatas em uma matriz de buffer.
Em seguida, execute a ação depois que o array não tiver sido modificado pelo tempo X usando um timer: - Redefina o timer toda vez que algo for gravado no buffer - Execute a ação no tick
Isso também captura outro tipo de duplicação. Se você modificar um arquivo dentro de uma pasta, a pasta também lançará um evento Change.
fonte
Esta solução funcionou para mim no aplicativo de produção:
Meio Ambiente:
VB.Net Framework 4.5.2
Defina manualmente as propriedades do objeto: NotifyFilter = Size
Então use este código:
fonte
Tente isso!
fonte
Eu tive que combinar várias idéias das postagens acima e adicionar uma verificação de bloqueio de arquivos para que funcionasse para mim:
fonte
Abordei o problema de criação dupla como este, que ignora o primeiro evento:
fonte