FileSystemWatcher x sondagem para observar alterações no arquivo

152

Preciso configurar um aplicativo que observe os arquivos sendo criados em um diretório, localmente ou em uma unidade de rede.

Será que a FileSystemWatcherpesquisa ou em um timer seria a melhor opção. Eu usei os dois métodos no passado, mas não extensivamente.

Quais problemas (desempenho, confiabilidade etc.) existem em ambos os métodos?

Jon Tackabury
fonte
3
O FileSystemWatcher é uma abstração com vazamento e não pode ser invocado apenas para os casos mais básicos. Veja aqui: stackoverflow.com/a/22768610/129130
Stein Åsmul
1
Deseja adicionar um link para referência a esta resposta por Raymond Chen (especialista da Microsoft) no tópico de confiabilidade do FileSystemWatcher . E seu blog: The Old New Thing (procure por FileSystemWatcher por exemplo).
Stein Åsmul

Respostas:

105

Vi o observador do sistema de arquivos falhar nos ambientes de produção e teste. Agora considero uma conveniência, mas não a considero confiável. Meu padrão é observar alterações no observador do sistema de arquivos, mas sondar ocasionalmente para detectar alterações ausentes nos arquivos.

Editar: se você tiver uma interface do usuário, também poderá dar ao usuário a capacidade de "atualizar" as alterações em vez de pesquisar. Eu combinaria isso com um observador do sistema de arquivos.

Jason Jackson
fonte
11
Eu vi se cair também. A solução que usamos é agrupar nossa própria classe, onde a classe wrapper TAMBÉM usa um timer para verificar se o observador ainda está em andamento.
Joel Coehoorn
Fazemos algo semelhante - depois que processamos o arquivo passado para o evento FileCreated, fazemos uma verificação manual de qualquer outro arquivo novo antes de retornar. Isso parece atenuar os problemas que ocorrem com muitos arquivos chegando ao mesmo tempo.
John Sibly 27/10/08
4
Acredito que o testamos no XP e no Server 2003 em um diretório local e em um compartilhamento de arquivos, e possuímos máquinas XP em campo. Tivemos problemas com o diretório local e o compartilhamento de arquivos. Uma das causas prováveis ​​que encontramos foi a cópia / criação de muitos arquivos em um curto período de tempo no diretório.
Jason Jackson
5
Não é muito construtivo nem profissional dizer apenas "eu vi um fantasma um dia". Parece que as pessoas no segmento, mencionando o documento msdn sobre saturações de buffer que não podem ser paginadas em páginas podem explicar seus problemas. Você já tentou usar a abordagem de Brent?
v.oddou
4
Acabei de comprar um sensor de gás na Amazon e fiquei impressionado com o número de pessoas que disseram que não funcionava, quando obviamente não o calibraram corretamente ou nem sequer sabiam sobre a calibração ... O FileSystemWatcher conhece limitações com alto tráfego de seu tamanho do buffer. Quase garantido, esse é o motivo para "falhar". Isso é explicado prontamente na documentação e existem soluções alternativas que fornecem uma operação muito confiável (conforme publicado abaixo). Esta não é uma boa resposta para apenas dizer "errado, algo não funcionou dessa vez, não sei por que ... ninguém deve confiar nisso".
u8it
60

O maior problema que tive foi a falta de arquivos quando o buffer ficou cheio. Fácil de corrigir, basta aumentar o buffer. Lembre-se de que ele contém os nomes e eventos dos arquivos, então aumente para a quantidade esperada de arquivos (tentativa e erro). Ele usa memória que não pode ser paginada e, portanto, pode forçar outros processos a paginar se a memória ficar baixa.

Aqui está o artigo do MSDN sobre o buffer: FileSystemWatcher .. ::. InternalBufferSize Property

Por MSDN:

Aumentar o tamanho do buffer é caro, pois vem da memória não paginada que não pode ser trocada para o disco, portanto, mantenha o buffer o menor possível. Para evitar um estouro de buffer, use as propriedades NotifyFilter e IncludeSubdirectories para filtrar as notificações de alteração indesejadas.

Usamos 16 MB devido a um grande lote esperado ao mesmo tempo. Funciona bem e nunca perde um arquivo.

Também lemos todos os arquivos antes de começar a processar um único ... obtemos os nomes dos arquivos armazenados em cache com segurança (no nosso caso, em uma tabela de banco de dados) e depois os processamos.

Para problemas de bloqueio de arquivos, inicio um processo que aguarda o desbloqueio do arquivo, aguardando um segundo, depois dois, depois quatro, etc. Nós nunca votamos. Isso está em produção sem erros há cerca de dois anos.


fonte
12
Estouro de buffer? Oh, você quer dizer estouro de pilha.
TheFlash 19/10/09
1
A partir do .NET 3.5: "Você pode definir o buffer para 4 KB ou mais, mas ele não deve exceder 64 KB"
brad
9
Como você está usando 16 MB se o buffer interno máximo do FileSystemWatcher é de 64 KB?
BK
1
@ Jarvis, um buffer é um local de armazenamento moderado configurado para reter as informações conforme elas são transmitidas até que possam ser processadas, isso geralmente significa um FIFO ou Fila, pois você deseja lidar com solicitações na ordem em que elas chegam, no entanto, em alguns processos, como recursão em programas um FILO ou estrutura Stack é o que é utilizado, neste caso, estamos definitivamente referindo-se ao evento fila de buffer e não os programas chamam pilha de buffer
miket
1
petermeinl.wordpress.com/2015/05/18/tamed-filesystemwatcher Esta postagem compartilha invólucros robustos em torno dos problemas de correção padrão do FileSystemWatcher (FSW) encontrados normalmente ao usá-lo para monitorar o sistema de arquivos em aplicativos do mundo real.
18718 Kiquenet
35

o FileSystemWatcher pode perder alterações durante os horários de pico, se o número de alterações na fila exceder o buffer fornecido. Isso não é uma limitação da classe .NET em si, mas da infraestrutura subjacente do Win32. Em nossa experiência, a melhor maneira de minimizar esse problema é desenfileirar as notificações o mais rápido possível e lidar com elas em outro encadeamento.

Conforme mencionado por @ChillTemp acima, o observador pode não funcionar em compartilhamentos que não são do Windows. Por exemplo, ele não funcionará em todas as unidades Novell montadas.

Concordo que um bom compromisso é fazer uma pesquisa ocasional para captar as alterações perdidas.

Brent Rockwood
fonte
4
O observador do sistema de arquivos pode começar a gerar muitos eventos em rápida sucessão. Se você não puder executar seu manipulador de eventos pelo menos tão rapidamente quanto eles estão sendo disparados, eventualmente, o manipulador começará a soltar eventos no chão e você perderá as coisas.
Brent Rockwood
17

Observe também que o observador do sistema de arquivos não é confiável em compartilhamentos de arquivos. Especialmente se o compartilhamento de arquivos estiver hospedado em um servidor não Windows. O FSW não deve ser usado para nada crítico. Ou deve ser usado com uma pesquisa ocasional para verificar se não perdeu nada.

chilltemp
fonte
3
A Microsoft reconheceu que não é confiável em compartilhamentos de arquivos que não são do Windows? Certamente, estamos experimentando isso em primeira mão desde a mudança de um compartilhamento do Windows para um compartilhamento SMB baseado no Linux.
26412 Sean
1
Não que eu saiba. E tenho certeza de que seria simplesmente um jogo de culpa entre os diferentes fornecedores.
Chilltemp
1
Ocorreu um problema com o inspetor do sistema de arquivos em unidades mapeadas. Se o mapa for desconectado e reconectado, o observador de arquivos não fará mais alterações. Facilmente resolvido, mas ainda um ataque ao IMHO, observador do sistema de arquivos.
Richard Dorman
11

Pessoalmente, usei o FileSystemWatchersistema de produção e funcionou bem. Nos últimos 6 meses, ele não teve um único soluço executando 24x7. Ele está monitorando uma única pasta local (que é compartilhada). Temos um número relativamente pequeno de operações de arquivo com as quais ele deve lidar (10 eventos disparados por dia). Não é algo que eu já tive que me preocupar. Eu o usaria novamente se tivesse que refazer a decisão.

Jim
fonte
7

Atualmente, uso o FileSystemWatcherarquivo XML em atualização em média a cada 100 milissegundos.

Descobri que, enquanto o FileSystemWatcherestiver configurado corretamente, você nunca deverá ter problemas com arquivos locais .

Não tenho experiência em observação remota de arquivos e compartilhamentos que não são do Windows.

Considero que a pesquisa do arquivo é redundante e não vale a pena a sobrecarga, a menos que você confie inerentemente FileSystemWatcherou tenha experimentado diretamente as limitações que todos os outros aqui listaram (compartilhamentos que não são do Windows e observação remota de arquivos).

PersistenceOfVision
fonte
5

Eu iria com a votação.

Problemas de rede fazem FileSystemWatchercom que isso não seja confiável (mesmo ao sobrecarregar o evento de erro).

azulado
fonte
5

Ocorreu um problema ao usar FileSystemWatchercompartilhamentos de rede. Se você estiver em um ambiente Windows puro, pode não ser um problema, mas eu estava assistindo a um compartilhamento NFS e, como o NFS é sem estado, nunca houve uma notificação quando o arquivo que eu estava assistindo foi alterado.

Jon Norton
fonte
Eu encontrei o mesmo problema, mas foi inesperado para mim, pois o FileSystemWatcher estava no mesmo servidor Windows que compartilha a pasta usando o NFS. o fato de compartilhar uma pasta com o NFS faz com que o filesystemwatcher não veja os arquivos criados usando o compartilhamento remotamente (ou seja, de um Linux que mapeia o compartilhamento), enquanto se eu escrever um arquivo na mesma pasta sob monitoramento, o filesystemwatcher será acionado. parece que o servidor NFS grava arquivos usando uma camada inferior e a camada API que aciona o observador do sistema de arquivos não está envolvida, alguém tem mais informações?
Mosè Bottacini
3

Tive alguns problemas com o FSW em unidades de rede: a exclusão de um arquivo sempre gerava o evento de erro, nunca o evento excluído. Como não encontrei uma solução, agora evito o FSW e uso a pesquisa.

Por outro lado, os eventos de criação funcionaram bem; portanto, se você precisar apenas observar a criação do arquivo, poderá ir para o FSW.

Além disso, não tive problemas nas pastas locais, independentemente de serem compartilhadas ou não.

Treb
fonte
3

Retornando do método de evento o mais rápido possível, usando outro encadeamento, resolvi o problema para mim:

private void Watcher_Created(object sender, FileSystemEventArgs e)
{
    Task.Run(() => MySubmit(e.FullPath));
}
spludlow
fonte
2

Usar o FSW e a pesquisa é um desperdício de tempo e recursos, na minha opinião, e estou surpreso que desenvolvedores experientes o sugiram. Se você precisar usar a pesquisa para verificar qualquer "falha no FSW", naturalmente poderá descartar o FSW completamente e usar apenas a pesquisa.

Atualmente, estou tentando decidir se usarei o FSW ou pesquisarei um projeto que desenvolvo. Lendo as respostas, é óbvio que há casos em que o FSW cobre perfeitamente as necessidades, enquanto outras vezes você precisa pesquisar. Infelizmente, nenhuma resposta realmente lidou com a diferença de desempenho (se houver), apenas com os problemas de "confiabilidade". Existe alguém que possa responder a essa parte da pergunta?

EDIT: o ponto de nmclean para a validade do uso do FSW e da pesquisa (você pode ler a discussão nos comentários, se estiver interessado) parece ser uma explicação muito racional por que pode haver situações em que o uso do FSW e da pesquisa é eficiente. Obrigado por esclarecer isso para mim (e para qualquer pessoa que tenha a mesma opinião), nmclean .

ThunderGr
fonte
1
E se você quiser responder às alterações do arquivo o mais rápido possível? Se você pesquisar uma vez por minuto, por exemplo, pode ter um atraso de até 1 minuto entre a alteração de um arquivo e o aplicativo que está recebendo a alteração. O evento FSW provavelmente seria acionado muito antes disso. Portanto, usando os dois, você está lidando com os eventos com o menor atraso possível, mas também captando os eventos perdidos, se houver algum.
rom99
@ rom99 Exatamente o meu ponto. Se o FSW não for confiável nos casos em que você precisar de resposta rápida, não faz sentido usá-lo, pois você terá casos em que não haverá resposta rápida; portanto, seu aplicativo não será confiável. Polling em intervalos mais curtos, em um thread, seria o que você precisa fazer. Ao fazer as duas coisas , significa que você tem uma tolerância nos tempos de resposta que a pesquisa cobre; portanto, por que não usar apenas pesquisas?
ThunderGr
5
@ThunderGr "assim, seu aplicativo não será confiável." - Em muitos casos, a velocidade não é um pré-requisito para a confiabilidade. O trabalho deve ser concluído, mas pode esperar um pouco. Se combinarmos a pesquisa lenta e confiável com o FSW rápido e não confiável , obteremos um aplicativo sempre confiável e, às vezes, rápido, que é melhor do que confiável e nunca rápido. Podemos remover o FSW e obter o mesmo tempo máximo de resposta fazendo sondagens constantes, mas isso ocorre às custas da capacidade de resposta do restante do aplicativo, portanto, isso só deve ser feito se a resposta imediata for absolutamente necessária.
nmclean
2
Agora, por que o argumento acima é péssimo? Porque, embora ainda precisemos de acesso ao disco, precisamos menos . Da mesma forma, você pode pesquisar menos. Só porque ainda verificamos todos os arquivos, não significa que a carga de trabalho seja a mesma. Sua declaração, "a pesquisa é cara no tempo da CPU com FSW ou não", é falsa . Ao descarregar a preocupação de "imediatismo" para o FSW, podemos alterar a pesquisa para uma tarefa ociosa e de baixa prioridade, de modo que a ocupação do aplicativo em um determinado momento seja reduzida drasticamente e, ao mesmo tempo, forneça o "tratamento" do imediatismo. Você simplesmente não pode alcançar o mesmo equilíbrio apenas com a pesquisa.
nmclean
9
@nmclean Obrigado por dedicar tempo e energia para esclarecer isso da maneira que você fez. Quando você coloca dessa maneira, certamente faz muito mais sentido. Assim como há momentos em que um cache não é adequado ao seu problema específico, o FSW (quando se provar não confiável) pode não ser adequado. Acontece que você estava certo o tempo todo. Lamento ter demorado tanto tempo para eu conseguir.
ThunderGr 31/01
1

Solução de trabalho para trabalhar com criar evento em vez de alterar

Mesmo para copiar, cortar, colar, mover.

class Program
{        

        static void Main(string[] args)
        {
            string SourceFolderPath = "D:\\SourcePath";
            string DestinationFolderPath = "D:\\DestinationPath";
            FileSystemWatcher FileSystemWatcher = new FileSystemWatcher();
            FileSystemWatcher.Path = SourceFolderPath;
            FileSystemWatcher.IncludeSubdirectories = false;
            FileSystemWatcher.NotifyFilter = NotifyFilters.FileName;   // ON FILE NAME FILTER       
            FileSystemWatcher.Filter = "*.txt";         
             FileSystemWatcher.Created +=FileSystemWatcher_Created; // TRIGGERED ONLY FOR FILE GOT CREATED  BY COPY, CUT PASTE, MOVE  
            FileSystemWatcher.EnableRaisingEvents = true;

            Console.Read();
        }     

        static void FileSystemWatcher_Created(object sender, FileSystemEventArgs e)
        {           
                string SourceFolderPath = "D:\\SourcePath";
                string DestinationFolderPath = "D:\\DestinationPath";

                try
                {
                    // DO SOMETING LIKE MOVE, COPY, ETC
                    File.Copy(e.FullPath, DestinationFolderPath + @"\" + e.Name);
                }
                catch
                {
                }          
        }
}

Solução para esse observador de arquivos enquanto o evento de alteração de atributo do arquivo usando armazenamento estático

class Program
{
    static string IsSameFile = string.Empty;  // USE STATIC FOR TRACKING

    static void Main(string[] args)
    {
         string SourceFolderPath = "D:\\SourcePath";
        string DestinationFolderPath = "D:\\DestinationPath";
        FileSystemWatcher FileSystemWatcher = new FileSystemWatcher();
        FileSystemWatcher.Path = SourceFolderPath;
        FileSystemWatcher.IncludeSubdirectories = false;
        FileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite;          
        FileSystemWatcher.Filter = "*.txt";         
        FileSystemWatcher.Changed += FileSystemWatcher_Changed;
        FileSystemWatcher.EnableRaisingEvents = true;

        Console.Read();
    }     

    static void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
    {
        if (e.Name == IsSameFile)  //SKIPS ON MULTIPLE TRIGGERS
        {
            return;
        }
        else
        {
            string SourceFolderPath = "D:\\SourcePath";
            string DestinationFolderPath = "D:\\DestinationPath";

            try
            {
                // DO SOMETING LIKE MOVE, COPY, ETC
                File.Copy(e.FullPath, DestinationFolderPath + @"\" + e.Name);
            }
            catch
            {
            }
        }
        IsSameFile = e.Name;
    }
}

Esta é uma solução alternativa para esse problema de múltiplos eventos de disparo.

Mark Macneil Bikeio
fonte
0

Eu diria que use polling, especialmente em um cenário TDD, pois é muito mais fácil zombar / stub a presença de arquivos ou quando o evento de polling for acionado do que confiar no evento fsw mais "não controlado". + por ter trabalhado em vários aplicativos afetados por erros de fsw.

user2819502
fonte