Читать из растущего файла в C #? - PullRequest
16 голосов
/ 11 сентября 2009

В C # /. NET (в Windows) есть способ прочитать «растущий» файл, используя файловый поток? Длина файла будет очень мала при открытии файлового потока, но файл будет записан другим потоком. Если / когда файловый поток «догоняет» другой поток (т. Е. Когда Read() возвращает 0 прочитанных байтов), я хочу сделать паузу, чтобы позволить файлу немного буферизоваться, а затем продолжить чтение.

Я действительно не хочу использовать FilesystemWatcher и продолжать создавать новые файловые потоки (как было предложено для файлов журналов), поскольку это не файл журнала (это видеофайл, кодируемый на лету) и производительность - это проблема.

Спасибо
Роберт

Ответы [ 4 ]

6 голосов
/ 11 сентября 2009

Вы можете сделать это, но вам нужно тщательно отслеживать позиции чтения и записи файла, используя Stream.Seek и с соответствующей синхронизацией между потоками. Обычно вы используете EventWaitHandle или его подкласс для синхронизации данных, и вам также необходимо учитывать синхронизацию для доступа к самому объекту FileStream (возможно, с помощью оператора lock).

Обновление: Отвечая на на этот вопрос Я реализовал нечто подобное - ситуацию, когда файл загружался в фоновом режиме, а также загружался одновременно. Я использовал буферы памяти и опубликовал gist , в котором есть рабочий код. (Это GPL, но это может не иметь значения для вас - в любом случае вы можете использовать принципы, чтобы делать свое дело.)

4 голосов
/ 22 июля 2012

Это работало с StreamReader вокруг файла, со следующими шагами:

  1. В программе, которая пишет в файл, откройте его с совместным доступом для чтения, например:

    var out = new StreamWriter(File.Open("logFile.txt",  FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read));
    
  2. В программе, которая читает файл, откройте его с общим доступом для чтения и записи, например:

    using (FileStream fileStream = File.Open("logFile.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
    using ( var file = new StreamReader(fileStream))
    
  3. Прежде чем получить доступ к входному потоку, проверьте, достигнут ли конец, и если да, подождите некоторое время.

    while (file.EndOfStream)
    {
        Thread.Sleep(5);
    }
    
4 голосов
/ 11 сентября 2009

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

Вызов FileStream.length на самом деле очень медленный, у меня не было проблем с производительностью в моем решении (я читал «журнал» в диапазоне от 10 МБ до 50 ish).

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

2 голосов
/ 11 сентября 2009

Еще одна вещь, которая может быть полезна, - это класс FileStream, имеющий свойство ReadTimeOut, которое определяется как:

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

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

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

...