Leitura alterações em um arquivo em tempo real usando .NET
-
01-07-2019 - |
Pergunta
Eu tenho um arquivo .csv que é atualizado com freqüência (cerca de 20 a 30 vezes por minuto). Eu quero inserir as linhas recém-adicionadas a um banco de dados assim que eles são escritos para o arquivo.
FileSystemWatcher classe escutas para o arquivo notificações de alteração do sistema e pode elevar um evento sempre que há uma mudança em um arquivo especificado. O problema é que o FileSystemWatcher não pode determinar exatamente quais linhas foram adicionadas ou removidas (tanto quanto eu sei).
Uma maneira de ler essas linhas é salvar e comparar a contagem de linhas entre as mudanças e ler a diferença entre o último e penúltimo mudança. No entanto, eu estou procurando um aspirador de solução (talvez mais elegante).
Solução
Eu escrevi algo muito semelhante. Eu usei o FileSystemWatcher para receber notificações sobre alterações. Então, usei um FileStream para ler os dados (mantendo o controle de minha última posição dentro do arquivo e procurando que antes de ler os novos dados). Então eu adicionar os dados lidos para um buffer que extrai automaticamente linhas completas e, em seguida, saídas, em seguida, para a interface do usuário.
. Nota: "this.MoreData (..) é um evento, o ouvinte dos quais contribui para o tampão acima mencionado, e alças a extracção linha completa ??p>
Nota: Como já foi mencionado, isto só irá funcionar se as modificações são sempre adições ao arquivo. As eventuais supressões causará problemas.
Espero que isso ajude.
public void File_Changed( object source, FileSystemEventArgs e )
{
lock ( this )
{
if ( !this.bPaused )
{
bool bMoreData = false;
// Read from current seek position to end of file
byte[] bytesRead = new byte[this.iMaxBytes];
FileStream fs = new FileStream( this.strFilename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite );
if ( 0 == this.iPreviousSeekPos )
{
if ( this.bReadFromStart )
{
if ( null != this.BeginReadStart )
{
this.BeginReadStart( null, null );
}
this.bReadingFromStart = true;
}
else
{
if ( fs.Length > this.iMaxBytes )
{
this.iPreviousSeekPos = fs.Length - this.iMaxBytes;
}
}
}
this.iPreviousSeekPos = (int)fs.Seek( this.iPreviousSeekPos, SeekOrigin.Begin );
int iNumBytes = fs.Read( bytesRead, 0, this.iMaxBytes );
this.iPreviousSeekPos += iNumBytes;
// If we haven't read all the data, then raise another event
if ( this.iPreviousSeekPos < fs.Length )
{
bMoreData = true;
}
fs.Close();
string strData = this.encoding.GetString( bytesRead );
this.MoreData( this, strData );
if ( bMoreData )
{
File_Changed( null, null );
}
else
{
if ( this.bReadingFromStart )
{
this.bReadingFromStart = false;
if ( null != this.EndReadStart )
{
this.EndReadStart( null, null );
}
}
}
}
}
Outras dicas
Right, o FileSystemWatcher não sabe nada sobre o conteúdo de seu arquivo. Vai dizer-lhe se ele mudou, etc., mas não o que mudou.
Você está adicionando apenas para o arquivo? Foi um pouco claro a partir do posto de saber se linhas foram adicionados ou também pode ser removido. Supondo que eles são anexados, a solução é bastante simples, caso contrário, você estará fazendo algumas comparações.
Eu acho que você deve usar NTFS Change Journal ou similar:
O diário de alteração é usado por NTFS para fornecer um log persistente de todas alterações feitas nos arquivos no volume. Para cada volume, o NTFS usa a mudança revista para rastrear informações sobre acrescentados, apagados e modificados arquivos . O diário de alteração é muito mais eficiente do que carimbos de tempo ou arquivo notificações para determinar mudanças em um determinado espaço de nomes.
Você pode encontrar uma href="http://www.microsoft.com/technet/prodtechnol/windows2000serv/reskit/core/fncc_fil_khzt.mspx?mfr=true" rel="nofollow descrição no TechNet . Você vai precisar usar PInvoke em .NET.
Gostaria de manter o texto atual na memória se ele é pequeno o suficiente e, em seguida, utilizar um algoritmo de comparação para verificar se o novo texto e texto anterior mudou. Esta biblioteca, http://www.mathertel.de/Diff/ , não só lhe dirá que alguma coisa mudou, mas o que mudou também. Então você pode inserir os dados alterados na base de dados.
fora do topo da minha cabeça, você pode armazenar o último tamanho do arquivo conhecido. Verifique contra o tamanho do arquivo, e quando ela muda, abra um leitor.
Em seguida, procure o leitor para o seu tamanho último arquivo, e começar a ler a partir daí.
Você está certo sobre o FileSystemWatcher. Você pode ouvir criados, apagados, etc. eventos modificados, mas você não conseguir mais profundo do que o arquivo que os criou.
Você tem controle sobre o próprio arquivo? Você poderia mudar o modelo ligeiramente para usar o arquivo como um buffer. Em vez de um arquivo, tenho dois. Uma delas é a encenação, uma é a soma de toda a saída processada. Leia todas as linhas do seu "tampão" arquivo, processá-los, em seguida, inseri-los no final do outro arquivo que é o total de todas as linhas de processados. Em seguida, exclua as linhas que você processados. Desta forma, todas as informações no seu arquivo está pendente de processamento. O problema é que se o sistema for diferente de gravação (ou seja, também exclui linhas), então ele não vai funcionar.