Leia de um arquivo em crescimento em C#?
-
05-07-2019 - |
Pergunta
Em C#/. Net (no Windows), existe uma maneira de ler um arquivo "cultivo" usando um fluxo de arquivo? O comprimento do arquivo será muito pequeno quando o Filestream for aberto, mas o arquivo será gravado por outro thread. Se/quando o FileStream "alcança" o outro tópico (ou seja, quando Read()
Retorna 0 bytes Leia), quero pausar para permitir que o arquivo buffer um pouco e continue lendo.
Eu realmente não quero usar um FilesystemWatcher
e continue criando novos fluxos de arquivo (como foi sugerido para arquivos de log), pois este não é um arquivo de log (é um arquivo de vídeo que está sendo codificado em tempo real) e o desempenho é um problema.
Obrigado,
Robert
Solução
Você pode fazer isso, mas precisa acompanhar cuidadosamente o arquivo de leitura e gravação de posições usando Stream.Seek
e com a sincronização apropriada entre os threads. Normalmente você usaria um EventWaitHandle
ou sua subclasse para fazer a sincronização para dados, e você também precisaria considerar a sincronização para o acesso ao FileStream
o próprio objeto (provavelmente por meio de um lock
declaração).
Atualizar: Em responder essa questão Implementei algo semelhante - uma situação em que um arquivo estava sendo baixado em segundo plano e também sendo carregado ao mesmo tempo. Eu usei buffers de memória e publiquei um essência que tem código de trabalho. (É GPL, mas isso pode não importar para você - em qualquer caso, você pode usar os princípios para fazer suas próprias coisas.)
Outras dicas
A maneira como eu resolvi isso é usar o DirectoryWatcher / FileSystemWatcher Class e, quando desencadeia o arquivo que você deseja, você abra uma transmissão file e a leia até o final. E quando terminar de ler, salvo a posição do leitor, então da próxima vez DirectoryWatcher / FileSystemwatcher gatilhos Eu abro um fluxo Definir a posição para onde estava da última vez.
Chamando filestream.length é realmente muito lento, não tive problemas de desempenho com minha solução (eu estava lendo um "log" que varia de 10 MB a 50 ISH).
Para mim, a solução que descrevo é muito simples e fácil de manter, eu tentaria e perfilava. Eu não acho que você terá problemas de desempenho com base nisso. Faço isso quando as pessoas estão jogando um jogo com vários roscas, levando toda a sua CPU e ninguém reclamou que meu analisador é mais exigente do que os analisadores concorrentes.
Isso funcionou com um fluxo de fluxo em torno de um arquivo, com as seguintes etapas:
No programa que grava no arquivo, abra -o com o compartilhamento de leitura, assim:
var out = new StreamWriter(File.Open("logFile.txt", FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read));
No programa que lê o arquivo, abra-o com o compartilhamento de leitura e gravação, como este:
using (FileStream fileStream = File.Open("logFile.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using ( var file = new StreamReader(fileStream))
Antes de acessar o fluxo de entrada, verifique se o final foi atingido e, em caso afirmativo, espere um pouco.
while (file.EndOfStream) { Thread.Sleep(5); }
Outra coisa que pode ser útil é que a classe FileStream possui uma propriedade chamada ReadTimeout, que é definida como:
Obtém ou define um valor, em milissegundos, que determina quanto tempo o fluxo tentará ler antes de tempo. (herdado do fluxo)
Isso pode ser útil, pois, quando suas leituras, o seu tópico executa as leituras pode fazer uma pausa enquanto o buffer de gravação for liberado. Vale a pena escrever um pequeno teste para ver se essa propriedade ajudaria sua causa de alguma forma.
As operações de leitura e gravação estão acontecendo no mesmo objeto? Nesse caso, você pode escrever suas próprias abstrações sobre o arquivo e, em seguida, escreva o código de comunicação cruzado, de modo que o tópico que esteja executando as gravações e notifique o thread executando as leituras quando for feito para que o tópico que faz as leituras saiba quando parar de ler leia Quando atinge o EOF.