我有一个Python服务,可将日志分散到文本文件中.它每〜400KB旋转一次.因此,Python服务在文件上打开了一个句柄,我们将其称为app.log.然后,它会立即将内容写入文件,然后再次将其刷新到磁盘.当达到一定大小时,它将关闭其句柄,然后将其移至app.log.1并在app.log上启动新的句柄.
因此,我无法更改此服务,但是我有一个C#应用程序可以读取这些日志.我遇到了3种情况:
>如果我只是尝试使用新的FileStream(path,FileMode.Open);读取那些日志,则它将不允许我使用,因为Python服务上有一个句柄.
>如果我尝试使用新的FileStream(path,FileMode.Open,FileAccess.Read);来打开它,则允许我读取它,但是如果该服务尝试旋转日志,它将不能作为我的C#应用程序现在在文件上具有一个句柄.
>并且,如果我尝试使用新的FileStream(path,FileMode.Open,FileAccess.Read,FileShare.Delete);打开文件,我的Python服务不会在删除文件时失败,但是在创建新句柄时会失败app.log,因为C#应用程序仍将具有它的句柄.
我知道的唯一解决方案是使用Windows Shadow Copy(VSS)创建日志快照,然后读取该快照,但这将非常昂贵,因为我们需要每5分钟查询一次日志.
另外,我对读取轮换的日志app.log.1,app.log.2等不感兴趣.
使用所有锁定/句柄似乎很难在Windows下登录到文本文件.有人有什么建议吗?
解决方法:
您应该能够按照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应用程序是否编写了一些标记,您可以寻找这些标记来表示文件的结尾?它写的是“日志结尾”还是类似的东西?
还请注意,LogFile n-1不存在的时间将会很短.这是因为,如果您有日志文件0、1、2和3,则需要先将日志文件3转换为日志文件4,然后才能将日志文件2转换为日志文件3.拥有日志文件0、1、2、4和3的时间.
就我个人而言,我会发现为您的Python应用程序编写日志记录的开发人员首先会给他/她带来麻烦的罪恶之眼.最新的日志文件具有最大的数目怎么办?