Использование MemoryMappedFile и FileSystemWatcher для обнаружения новых записей в лог-файле - PullRequest
1 голос
/ 16 ноября 2010

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

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

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

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

Спасибо

Tom

EDIT:

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

EDITEDIT

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

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

Ответы [ 6 ]

2 голосов
/ 17 ноября 2010

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

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

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

0 голосов
/ 17 ноября 2010

Я сделал нечто похожее только для мониторинга файлов журналов на консоли (в отличие от обработки), но принципы те же. Как и вы, я использую FileSystemWatcher, и важная логика в моем обработчике событий 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;
}

, где lastPositions -

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

и DumpNewData просто

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);
}
0 голосов
/ 17 ноября 2010

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

var readerStream = new FileStream (путь, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

var mmf = MemoryMappedFile.CreateFromFile (readerStream, null, 0, MemoryMappedFileAccess.Read, null, HandleInheritability.None, false);

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

0 голосов
/ 17 ноября 2010

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

0 голосов
/ 16 ноября 2010

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

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

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

0 голосов
/ 16 ноября 2010

[Начать 2-е РЕДАКТИРОВАНИЕ]

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

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

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

[Конец 2-го РЕДАКТИРОВАНИЯ]

[Начать редактировать]

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

[Конец РЕДАКТИРОВАНИЯ]

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

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

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

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

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