C# - чтение из двоичного файла журнала, который обновляется каждые 6 секунд с 12 КБ данных

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

  •  19-09-2019
  •  | 
  •  

Вопрос

У меня есть двоичный файл журнала с потоковыми данными от датчика (Int16).
Каждые 6 секунд добавляются 6000 выборок типа Int16, пока датчик не отключится.

Мне нужно регулярно опрашивать этот файл, начиная с последней прочитанной позиции.Лучше ли а) держать FileStream и бинарного считывателя открытым и созданным между показаниями B) экземпляры FileStream и Binard Reader каждый раз, когда мне нужно читать (и держать внешнюю переменную, чтобы отслеживать последнюю позицию, прочитав) C) что -то лучше?

РЕДАКТИРОВАТЬ:К некоторым замечательным предложениям на данный момент необходимо добавить, что «серверное» приложение предоставляется сторонним поставщиком исходного кода и не может быть изменено.

Это было полезно?

Решение

Если он всегда добавляет один и тот же объем данных, возможно, имеет смысл открыть его снова.Возможно, вам захочется узнать длину, прежде чем открыть ее, а затем округлить до целого числа доступных «наборов выборок», на тот случай, если вы поймаете ее, пока она все еще записывает данные.Это может означать, что вы читаете меньше, чем вы мог прочитайте (если запись завершится между проверкой длины и началом чтения), но в следующий раз вы наверстаете упущенное.

Однако вам необходимо убедиться, что вы используете соответствующие параметры общего доступа, чтобы автор мог писать, пока вы читаете.(Автор, вероятно, тоже должен был писать это с учетом этого.)

Другие советы

Вы можете использовать ПамятьMappedFiles?

Если вы можете, сопоставив файл в памяти и разделив его между процессами, вы сможете читать данные, просто каждый раз увеличивая смещение для вашего указателя.

Если вы объедините это с событием, вы сможете сигнализировать читателю, когда он сможет прочитать информацию.Не нужно будет ничего блокировать, поскольку считыватель всегда будет читать «старые» данные, которые уже были записаны.

Я бы рекомендовал использовать каналы, они действуют так же, как файлы, за исключением потоковой передачи данных напрямую между приложениями, даже если приложения работают на разных компьютерах (хотя на самом деле это вариант только в том случае, если вы можете изменить оба приложения).Проверьте это в пространстве имен «System.IO.Pipes».

P.S.Для этого вы должны использовать «именованный» канал (каналы также поддерживаются в «c», поэтому практически любой полуприличный язык программирования должен иметь возможность их реализовать)

Я думаю, что (а) является лучшим, потому что:

  • Текущая позиция будет увеличиваться по мере чтения, и вам не нужно беспокоиться о том, чтобы ее где-то сохранить;
  • Вам не нужно открывать его и искать требуемую позицию (повторное открытие не должно быть намного медленнее, но, я считаю, что сохранение его открытым дает ОС некоторые подсказки для оптимизации) каждый раз, когда вы его опрашиваете;
  • Другие решения, которые я могу придумать, требуют PInvokes для примитивов системной межпроцессной синхронизации.И они не будут быстрее, чем файловые операции, уже реализованные в рамках фреймворка.

Вам просто нужно установить правильные флаги FileShare:

Просто для примера:

Сервер:

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
    }
}

Клиент:

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();
    }
}

вы также можете передавать данные в базу данных, а не в файл в качестве другой альтернативы, тогда вам не придется беспокоиться о блокировке файла.

но если вы застряли в файловом методе, возможно, вам захочется закрывать файл каждый раз, когда вы читаете из него данные;это во многом зависит от того, насколько сложным будет процесс записи в файл, и сможет ли он обнаружить операцию блокировки файла и отреагировать соответствующим образом без ужасных сбоев.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top