2010-11-16 52 views
1

我有一個由第三方應用程序編寫的日誌文件,我希望我的應用程序能夠實時/近時「讀取」該日誌文件,解析新日誌並根據某些事件採取行動。使用MemoryMappedFile和FileSystemWatcher檢測日誌文件的新條目

我的想法是,我可以通過FileSystemWatcher(用於信號文件更改)和MemoryMappedFile(從某個偏移量繼續讀取)的組合來實現此目的。

但是,由於這是我第一次使用MemoryMappedFiles,我遇到了一些可能由於不能正確理解概念而引起的問題(例如,我無法打開現有文件,因爲它正被另一個使用處理)。

我想知道是否有人有一個如何使用MemoryMappedFiles讀取被另一個進程鎖定的文件的例子?

感謝,

湯姆

編輯:

從評論,它看起來像內存映射文件不會幫我訪問有獨佔鎖文件。然而,「尾巴」工具例如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); 
+0

我做了一個評論關於詹姆斯的崗位所需要的文件共享參數的變化問題。一個MMF無法繞過一個完全鎖定的文件,如果是這樣的話,你會被卡住。 – 2010-11-16 21:10:38

+0

請看我上面的編輯。這個問題似乎更專注於解決MMF與FileStream之間的排他鎖問題。我已經嘗試了多個窗口尾部工具,他們似乎都能夠解決排他鎖只是好,任何想法他們如何實現這一目標? – TJF 2010-11-16 21:14:07

回答

1

回答我自己的問題,讀取鎖定文件的技巧是使用以下訪問標誌創建FileStream:

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

現在,它只是一個做任何基於輪詢間隔或尋找FileSystemWatcher的改變事件檢測文件

+0

您是否使用了MemoryMappedFile?我正在尋求實施相同的事情。 – Devela 2012-11-07 20:52:01

0

[開始第二次編輯]

一個更多的想法...

如果第三方應用程序恰好使用日誌框架,如NLog,l og4net或System.Diagnostics,您仍然可以編寫自己的Target/Appender/TraceListener,並將消息路由到您可以查看它們的某個位置(例如,不是專門打開的文件,另一個進程等)。

如果您的第三方應用程序正在使用日誌框架,我們可能已經聽說過它現在;-)

[結束第二次編輯]

[開始編輯]

我想我誤解了這個問題。它起初聽起來像是你正在使用一個第三方庫,它已經實現了日誌記錄,並且你想在生成日誌記錄的程序中進行解析。重讀您的問題後,聽起來好像您要從應用程序外部「聽」日誌文件。如果是這樣的話,我的答案可能不會幫助你。抱歉。

[編輯完]

我沒有什麼要提供有關MemoryMappedFiles,但我不知道,如果你能達到你所追求的通過編寫自定義監聽器/目標/附加器的第三方記錄系統?例如,如果您使用NLog,則可以編寫自定義目標並將所有日誌消息定向到那裏(同時也將它們引導到「真實」目標)。通過這種方式,您可以在記錄每條日誌消息時獲得破解(所以它實際上是實時的,而不是實時的)。你可以用log4net和System.Diagnostics做同樣的事情。

請注意,NLog甚至有一個「MethodCall」目標。要使用那個,你只需要寫一個具有正確簽名的靜態方法。我不知道log4net是否有類似的概念。

這似乎是比第三方軟件正在寫入的日誌文件更容易讀取和解析日誌文件。

0

我不確定MemoryMappedFiles是否會幫助你。看看的FileStream:

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

雖然如果第三方應用程序具有獨佔方式鎖定的文件,沒有太多,你可以做些什麼......

+0

好吧,使用FileStream,我無法讀取被另一個進程獨佔鎖定的文件,我希望能夠通過內存映射文件實現這一點。 Windows尾巴工具,如baretail(http://www.baremetalsoft.com/baretail/index.php)能夠讀取鎖定的文件,但很好,所以必須有一些方法來實現這個 – TJF 2010-11-16 21:06:15

+1

FileShare.Read不會爲了工作,寫入日誌文件的應用程序已經獲得了寫入權限。你不能否認已經獲得的權利。推測也是OP的問題。你*有*在這裏指定ReadWrite。 – 2010-11-16 21:08:53

0

如果文件是「使用」 ,對此沒有任何可以做的事情。它確實是「正在使用」。 MemoryMappedFiles用於讀取驅動器中的大量數據或與其他程序共享數據。它無助於避開「使用中」限制。

0

存儲器映射文件是在相同的限制,因此FileStream你初始化,請確保您初始化內存映射,文件中像這樣

VAR readerStream =新的FileStream(路徑,FileMode.Open,FileAccess的。閱讀,FileShare.ReadWrite); var mmf = MemoryMappedFile.CreateFromFile(readerStream,null,0,MemoryMappedFileAccess.Read,null,HandleInheritability.None,false);

如果其他進程已經完全鎖定它,即使寫入,你運氣不好,不知道是否有辦法。也許使用一些定時器檢測進程何時停止寫入。

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); 
} 
+0

不幸的是,這並沒有解決閱讀文件的排他鎖但 – TJF 2010-11-16 21:38:53