2014-12-01 68 views
3

我有一個Python服務將日誌分發到文本文件。它每旋轉〜400KB就會旋轉它們。所以Python服務打開文件的句柄,我們稱之爲app.log。然後,它會立即將文件寫入文件並將其刷新到磁盤。當它達到一定的大小時,它關閉它的句柄,並將其移動到app.log.1並開始新的句柄app.log閱讀循環日誌文件和文件鎖定

所以我不能改變這個服務,但我有一個C#應用程序將讀取這些日誌。我跑進3個場景:

  • 如果我只是試着去閱讀那些那些使用new FileStream(path, FileMode.Open);日誌,它不會允許我爲Python的服務上有一個手柄。
  • 如果我嘗試使用new FileStream(path, FileMode.Open, FileAccess.Read);打開它,它允許我讀取它,但是如果服務試圖旋轉日誌,它將無法如我的C#應用​​程序現在具有該文件的句柄。
  • 如果我嘗試使用new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Delete);打開文件,我的Python服務在刪除文件時不會失敗,但是它將無法在app.log上創建新的句柄,因爲C#應用程序仍然會處理它。

我知道的唯一解決方案是使用Windows Shadow Copy(VSS)創建日誌的快照,然後讀取該快照,但這會非常昂貴,因爲我們需要查詢日誌每5分鐘一班。

而且,我不感興趣,讀了循環日誌,app.log.1app.log.2

記錄爲文本的Windows下的文件似乎是一個什麼樣的痛苦與所有的鎖定/手柄。有沒有人有任何建議?

+0

所以在您的Python應用程序開始通過C#應用程序讀取舊的新的日誌文件的一半的情況下,你想要什麼發生?在轉移到新文件之前,C#應用程序是否應該繼續讀取舊文件的末尾?它是一個恥辱,你不能更新Python應用程序,因爲該編號方案是愚蠢的。 – 2014-12-12 12:34:48

+0

最重要的是我們無法更新Python應用程序。 C#應用程序可以靜靜地忽略任何讀取失敗,它應該停止閱讀並允許Python應用程序旋轉日誌(因此移動文件並創建一個新的日誌)。 C#服務檢查日誌以知道Python應用程序基本上正在執行。 – jValdron 2014-12-12 12:56:58

+0

請看便知這裏每週日誌輪換[https://stackoverflow.com/a/45028620/8288059](https://stackoverflow.com/a/45028620/8288059) – 2017-07-11 08:00:32

回答

3

你應該可以像Dmitry Popov在他的回答中所建議的那樣打開文件,而不會影響Python對它的寫入,但是它取決於Python應用程序在文件上保留的鎖,它可以完全鎖定你,沒有任何事情可以防止黑客入侵Windows。

FileSream fs = File.Open(@"c:\Test.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete) 

在這種方式創建的FileStream對象將仍然被連接到一個操作系統文件移動操作之後的相同的文件已經被在其上進行重命名。

因此,讓我們假設你的python應用程序打開一個名爲Test.log的文件並開始寫入它。你可以使用從上面的行返回的文件流來讀取寫入它的任何數據(在python刷新緩衝區之後)。 python應用程序可以關閉並重新打開文件,因爲它每次都需要寫入,閱讀應用程序將保持連接。當python應用程序發出文件移動操作將文件重命名爲Test1.log時,上面返回的文件流仍然會連接到現在稱爲Test1.log的文件,因此您可以在開始之前繼續讀取文件末尾新的日誌文件,如果這是你想要的。對此有一個警告。 Python應用程序需要使用移動/重命名操作,而不是將文件複製到新文件並刪除舊文件,但如果這是它的作用,我會感到驚訝。

有是你的閱讀應用程序將您的書面申請已經完成了從中讀取之前到達文件末尾的可能性。在這種情況下,fs.Read會在超時後保持返回0,直到寫入應用程序打開文件並寫入更多內容。如果你願意,你可以讓時間很長/無限。

當你不想開始新的一個你可以只結束前讀到一個文件的末尾,並定期重新打開該文件。沒有數字後綴的日誌文件應該始終是最新的。

然而,如果你希望你的閱讀應用起始於下一個,你需要制定出當寫應用程序已完成寫入日誌文件開始之前閱讀到一個日誌文件的末尾。還需要找出現在調用的文件,以便下一步可以讀取n-1。是否有一些由python應用程序編寫的標記,您可以查找以表示文件的結尾?它是否寫入'結束日誌'或類似的東西?

被警告也有將是很短的時間,當日志文件N-1不存在。這是因爲如果你有日誌文件0,1,2和3,它需要將日誌文件3寫入日誌文件4,然後才能將日誌文件2寫入日誌文件3中。雖然這樣做會有短暫的時間時間當你有日誌文件0,1,2,4和沒有3.

就我個人而言,我會找到開發人員爲你的Python應用程序編寫日誌記錄給他/她首先造成這種頭痛的邪惡眼睛。讓最近的日誌文件具有最大數量有什麼問題?

1
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) 
{ 
    //Do works 
} 

C#線程不鎖定在這種情況下的文件,你的Python腳本可以編寫和關閉文件創建另一個沒有僵局。

+0

如果Python試圖刪除文件並且C#線程正在讀取文件,會發生什麼情況?我對FileShare.Read的理解是,它允許其他文件讀取文件,但不能寫入或刪除它。從MSDN「允許隨後打開文件以供閱讀」:http://msdn.microsoft.com/en-us/library/system.io.fileshare%28v=vs.110%29.aspx – jValdron 2014-12-11 17:20:19

0

您可以結合FileShare標誌:

FileShare.Write | FileShare.Delete 

這裏有一個演示:

using (var cSharp = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Write | FileShare.Delete)) 
{ 
    // The Python service will be able to change and to rename the file: 
    using (var python = new FileStream(filename, FileMode.Open, FileAccess.Write, FileShare.Read)) 
    { 
    } 
    File.Move(filename, newFilename); 
} 

你將不得不處理併發。您可以使用FileSystemWatcher來監視文件更改。

+0

您能詳細說明您意味着「處理併發」? – jValdron 2014-12-12 12:16:52

+0

通常,您將打開一個文件並鎖定它的句柄,以確保文件內容在讀取時不會被意外修改。在你描述的場景中,文件句柄是共享的,內容可以通過用Python編寫的服務來修改,或者文件可以重命名。 – 2014-12-12 13:41:45

+0

@MartinBrown在他的回答中更詳細地介紹了它。 – 2014-12-12 13:51:19