Использование MemoryMappedFile и FileSystemWatcher для обнаружения новых записей в файле журнала

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

  •  11-10-2019
  •  | 
  •  

Вопрос

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

Я думал, что я мог бы достичь этого с помощью комбинации FileSystemWatcher (для сигнализации изменений файла) и MemoryMappedFile (для продолжения чтения с определенного смещения).

Однако, поскольку я впервые использую MemoryMappedFiles, я сталкиваюсь с некоторыми проблемами, которые, вероятно, возникают из-за неправильного понимания концепции (напримерЯ не могу открыть существующий файл, так как он используется другим процессом).

Мне было интересно, есть ли у кого-нибудь пример того, как использовать MemoryMappedFiles для чтения файла, который заблокирован другим процессом?

Спасибо,

Том

Редактировать:

Судя по комментариям, похоже, что файлы с отображением в памяти не помогут мне получить доступ к файлам с эксклюзивной блокировкой.Однако "хвостовые" инструменты, такие как, напримерBaretail (http://www.baremetalsoft.com/baretail/index.php) способны именно на это.У него нет проблем с чтением файла с эксклюзивной блокировкой из другого приложения с интервалом в 1 секунду).Значит, должен быть какой-то способ сделать это?

ОТРЕДАКТИРОВАННЫЙ ТЕКСТ:

Чтобы ответить на мой собственный вопрос, хитрость при открытии заблокированного файла заключается в создании FileStream со следующими флагами доступа:

fileStream = new System.IO.FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite);
Это было полезно?

Решение

Чтобы ответить на мой собственный вопрос, трюк в чтении заблокированного файла создает FileStream со следующими флагами доступа:

FileStream fileStream = new System.IO.FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite);

Теперь это просто вопрос либо проведения опроса на основе интервалов, либо поиск событий FileSystemWatcher Изменения для обнаружения изменений файла

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

Я не уверен, что MemoryMappedFiles поможет вам. Взгляните на FileStream:

var stream = new FileStream(path, FileMode.Open, FileShare.Read);
stream.Seek(offset, SeekOrigin.Begin);

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

[Начать 2-ю ПРАВКУ]

Еще одна идея...

Если стороннее приложение использует платформу ведения журнала, такую как NLog, log4net или System.При диагностике вы все равно могли бы написать свой собственный Target / Appender / TraceListener и направлять сообщения куда-нибудь, где вы могли бы их просмотреть (например, в файл, который не открывается исключительно, в другой процесс и т.д.).

Если бы ваше стороннее приложение использовало платформу ведения журнала, мы, вероятно, уже слышали бы об этом ;-)

[Окончание 2-й ПРАВКИ]

[Начать ПРАВКУ]

Мне кажется, я неправильно истолковал вопрос.Сначала это звучало так, как будто вы использовали стороннюю библиотеку, в которой было реализовано ведение журнала, и вы хотели выполнить этот синтаксический анализ из программы, которая генерировала ведение журнала.Перечитав ваш вопрос, я понял, что вы хотите "прослушать" файл журнала извне приложения.Если это так, то мой ответ, вероятно, вам не поможет.Извините.

[Окончательная ПРАВКА]

Мне нечего предложить о MemoryMappedFiles, но мне интересно, могли бы вы достичь того, к чему стремитесь, написав пользовательский прослушиватель / target / appender для сторонней системы ведения журнала?

Например, если вы используете NLog, вы могли бы написать пользовательскую цель и направлять туда все ваши сообщения журнала (одновременно направляя их на "реальную" цель (цели)).Таким образом, вы получаете доступ к каждому сообщению журнала по мере его регистрации (так что на самом деле это происходит в режиме реального времени, а не вблизи реального времени).Вы могли бы сделать то же самое с log4net и System.Диагностика.

Обратите внимание, что у NLog даже есть цель "MethodCall".Чтобы использовать его, вам нужно всего лишь написать статический метод с правильной сигнатурой.Я не знаю, есть ли в log4net похожая концепция на эту.

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

Если файл «используется», с этим нет ничего, что можно сделать. Это действительно "в использовании". Memory Mamepoppels предназначены для чтения больших объемов данных с диска или обмена данными с другими программами. Это не поможет обойти ограничение «в использовании».

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

var ReaderStream = new FileStream (path, fileMode.open, fileCcess.read, fileshare.readwrite);

var mmf = memoryMappedFile.createFromFile (readerStream, null, 0, memoryMappedFileAccess.read, null, handlenhibality.none, false);

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

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

case WatcherChangeTypes.Changed:
{
    System.IO.FileInfo fi = new FileInfo(e.FullPath);

    long prevLength;

    if (lastPositions.TryGetValue(e.FullPath, out prevLength))
    {
        using (System.IO.FileStream fs = new FileStream(
           e.FullPath, FileMode.Open, FileAccess.Read))
        {
            fs.Seek(prevLength, SeekOrigin.Begin);
            DumpNewData(fs, (int)(fi.Length - prevLength));
            lastPositions[e.FullPath] = fs.Position;
        }
    }
    else
      lastPositions.Add(e.FullPath, fi.Length);

    break;
}

где есть последняя позиция

Dictionary<string, Int64> lastPositions = new Dictionary<string, long>();

И Sumpnewdata просто

private static void DumpNewData(FileStream fs, int bytesToRead)
{
    byte[] bytesRead = new byte[bytesToRead];
    fs.Read(bytesRead, 0, bytesToRead);
    string s = System.Text.ASCIIEncoding.ASCII.GetString(bytesRead);
    Console.Write(s);
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top