c # - leitura de arquivo de log binário que é atualizado a cada 6 segundos com 12k de dados

StackOverflow https://stackoverflow.com/questions/1170538

  •  19-09-2019
  •  | 
  •  

Pergunta

Eu tenho um arquivo de log binário com streaming de dados de um sensor (Int16).
A cada 6 segundos, 6000 amostras de tipo Int16 são adicionados, até que o sensor está desligado.

Eu preciso consultar este arquivo em intervalos regulares, continuando a partir da posição última leitura. É melhor a) manter um filestream e leitor de binário aberto e instanciado entre as leituras b) filestream instanciar e leitor de binário a cada vez que precisa ler (e manter uma variável externa para acompanhar a última leitura de posição) c) algo melhor?

EDIT:. Algumas ótimas sugestões até agora, necessidade de acrescentar que o app "servidor" é fornecido por um vendedor de fonte externa e não pode ser modificado

Foi útil?

Solução

Se ele está sempre adicionando a mesma quantidade de dados, pode fazer sentido para reabri-lo. Você pode querer descobrir o comprimento antes de abri-lo, e em seguida, volta para baixo para o número inteiro de "conjuntos de amostras" disponíveis, apenas no caso de você pegá-lo enquanto ele ainda está escrevendo os dados. Isso pode significar que você lê menos do que você poderia ler (se os acabamentos gravação entre você verificar o comprimento e iniciar a leitura), mas você vai pegar na próxima vez.

Você vai precisar para se certificar de que você usa as opções de compartilhamento adequadas para que o escritor ainda pode escrever enquanto você está lendo embora. (O escritor provavelmente terá que ter sido escrito com isso em mente também.)

Outras dicas

Você pode usar MemoryMappedFiles ?

Se você puder, mapear o arquivo na memória e compartilhá-lo entre os processos que você será capaz de ler os dados, basta incrementar o deslocamento para o ponteiro de cada vez.

Se você combiná-lo com um evento que você pode sinalizar seu leitor quando ele pode ir em uma ler as informações. Não haverá necessidade de bloquear qualquer coisa como o leitor vai sempre ler os dados "antigos", que já foi escrito.

Eu recomendaria usar tubos, eles agem como arquivos, exceto dados de fluxo diretamente entre as aplicações, mesmo que os aplicativos executados em diferentes PCs (embora isso é realmente apenas uma opção se você é capaz de alterar ambas as aplicações). Check it out sob o "System.IO.Pipes" namespace.

P.S. Você usaria um cachimbo "chamado" para isso (tubos são suportados em 'c', bem, então, basicamente, qualquer linguagem de programação decente metade deve ser capaz de implementá-las)

Eu acho que (a) é o melhor porque:

  • Posição atual será incrementado enquanto você lê e você não precisa se preocupar com a armazená-lo em algum lugar;
  • Você não precisa abri-lo e buscar a posição desejada (que não deve ser muito mais lento para reabrir, mas mantê-lo aberto dá OS algumas dicas para otimização eu acredito) cada vez que você sondar-lo;
  • Outras soluções que eu posso pensar fora requer PInvokes para primitivas de sincronização entre processos do sistema. E eles não vão ser mais rápido do que operações de arquivo já no quadro.

Você só precisa definir bandeiras FileShare adequada:

Apenas por exemplo:

Servidor:

using(var writer = new BinaryWriter(new FileStream(@"D:\testlog.log", FileMode.Append, FileAccess.Write, FileShare.Read)))
{
    int n;
    while(Int32.TryParse(Console.ReadLine(), out n))
    {
        writer.Write(n);
        writer.Flush(); // write cached bytes to file
    }
}

Cliente:

using (var reader = new BinaryReader(new FileStream(@"D:\testlog.log", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
{
    string s;
    while (Console.ReadLine() != "exit")
    {
        // allocate buffer for new ints
        Int32[] buffer = new Int32[(reader.BaseStream.Length - reader.BaseStream.Position) / sizeof(Int32)];

        Console.WriteLine("Stream length: {0}", reader.BaseStream.Length);
        Console.Write("Ints read: ");
        for (int i = 0; i < buffer.Length; i++)
        {
            buffer[i] = reader.ReadInt32();
            Console.Write((i == 0 ? "" : ", ") + buffer[i].ToString());
        }
        Console.WriteLine();
    }
}

Você também pode transmitir os dados em um banco de dados, ao invés de um arquivo como uma outra alternativa, então você não precisa se preocupar com o bloqueio de arquivos.

mas se você está preso com o método de arquivo, você pode querer fechar o arquivo cada vez que você ler dados a partir dele; isso depende um monte sobre o quão complicado o processo de escrita para o arquivo vai ser, e se ele pode detectar um arquivo de operação e responder apropriadamente bloqueio sem bater horrivelmente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top