我有一个由第三方应用程序编写的日志文件,我希望我的应用程序能够在实时/接近时间“读取”该日志文件,解析新的日志条目并对某些事件采取行动。
我的想法是,我可以通过FileSystemWatcher(用于指示文件更改)和MemoryMappedFile(从某个偏移量继续读取)的组合来实现此目的。
然而,由于这是我第一次使用MemoryMappedFiles,我确实遇到了一些问题,这些问题可能是因为没有正确理解这个概念(例如,我无法打开现有的文件,因为它正在被其他进程使用)。
我想知道是否有人有一个如何使用MemoryMappedFiles来读取被另一个进程锁定的文件的示例?
谢谢,
汤姆
编辑:
从评论中看,内存映射文件看起来不会帮助我访问具有独占锁定的文件。然而,“尾部”工具,例如, Baretail(http://www.baremetalsoft.com/baretail/index.php)能够做到这一点。读取具有1s间隔的另一个应用程序的独占锁定的文件没有问题)。那么,必须有一些方法来做到这一点?
EDITEDIT :
要回答我自己的问题,打开锁定文件的技巧是,使用以下访问标志创建FileStream:
fileStream = new System.IO.FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite);
答案 0 :(得分:2)
要回答我自己的问题,读取锁定文件的技巧是使用以下访问标志创建FileStream:
FileStream fileStream = new System.IO.FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite);
现在只需要进行基于间隔的轮询或查找FileSystemWatcher更改事件来检测文件更改
答案 1 :(得分:0)
[开始第二次编辑]
还有一个想法......
如果第三方应用程序碰巧使用NLog,log4net或System.Diagnostics等日志框架,您仍然可以编写自己的Target / Appender / TraceListener并将消息路由到可以查看它们的位置(例如未完全打开的文件,另一个进程等)。
如果你的第三方应用程序正在使用日志记录框架,我们现在可能已经听说过它了: - )
[第二次编辑]
[开始编辑]
我想我误解了这个问题。最初听起来像是在使用已实现日志记录的第三方库,并且您希望从生成日志记录的程序中进行此解析。重新阅读您的问题后,听起来您想要从应用程序外部“监听”日志文件。如果是这样的话,我的答案可能对你没有帮助。遗憾。
[编辑结束]
我对MemoryMappedFiles没有任何提供,但我想知道你是否可以通过为第三方日志系统编写自定义监听器/目标/ appender来实现你的目标?
例如,如果您使用的是NLog,则可以编写自定义Target并将所有日志消息定向到那里(同时还将它们指向“真实”目标)。通过这种方式,您可以记录每条日志消息(因此它实际上是实时的,而不是接近实时的)。您可以使用log4net和System.Diagnostics执行相同的操作。
请注意,NLog甚至还有一个“MethodCall”目标。要使用那个,你只需要编写一个带有正确签名的静态方法。我不知道log4net是否有与此类似的概念。
这似乎比在第三方软件写入时尝试读取和解析日志文件更容易工作。
答案 2 :(得分:0)
我不确定MemoryMappedFiles是否会帮助你。看一下FileStream:
var stream = new FileStream(path, FileMode.Open, FileShare.Read);
stream.Seek(offset, SeekOrigin.Begin);
虽然如果第三方应用程序将文件专门锁定,那么您可以做的事情并不多......
答案 3 :(得分:0)
如果文件“正在使用”,则无法完成任何操作。它真的是“在使用中”。 MemoryMappedFiles用于从驱动器读取大量数据或与其他程序共享数据。它无助于解决“使用中”限制。
答案 4 :(得分:0)
内存映射文件与初始化它的FileStream具有相同的限制,请确保初始化像这样的内存映射文件
var readerStream = new FileStream(path,FileMode.Open,FileAccess.Read,FileShare.ReadWrite);
var mmf = MemoryMappedFile.CreateFromFile(readerStream,null,0,MemoryMappedFileAccess.Read,null,HandleInheritability.None,false);
如果其他一些过程完全锁定了它,即使写下你运气不好,也不确定是否有办法解决这个问题。也许使用一些计时器会检测进程何时停止写入它。
答案 5 :(得分:0)
我做过类似的事情只是为了监控控制台上的日志文件(而不是处理),但原理是一样的。像你一样,我使用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);
}