【发布时间】:2013-10-14 07:31:13
【问题描述】:
我有一个程序不断将其日志写入文本文件。 我没有它的源代码,所以我不能以任何方式修改它,它也受到 Themida 的保护。
我需要读取日志文件并根据文件的内容执行一些脚本。 我无法删除该文件,因为不断写入该文件的程序已锁定该文件。 那么读取文件并仅读取文件的新行的更好方法是什么? 保存最后一行的位置?或者有什么东西可以在 C# 中解决它?
【问题讨论】:
我有一个程序不断将其日志写入文本文件。 我没有它的源代码,所以我不能以任何方式修改它,它也受到 Themida 的保护。
我需要读取日志文件并根据文件的内容执行一些脚本。 我无法删除该文件,因为不断写入该文件的程序已锁定该文件。 那么读取文件并仅读取文件的新行的更好方法是什么? 保存最后一行的位置?或者有什么东西可以在 C# 中解决它?
【问题讨论】:
也许使用FileSystemWatcher 以及使用 FileShare 打开文件(因为它正在被另一个进程使用)。 Hans Passant 为这部分提供了一个很好的答案here:
var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using (var sr = new StreamReader(fs)) {
// etc...
}
看看这个question 和接受的答案,这可能也有帮助。
【讨论】:
using (var fs = new FileStream("test.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete))
using (var reader = new StreamReader(fs))
{
while (true)
{
var line = reader.ReadLine();
if (!String.IsNullOrWhiteSpace(line))
Console.WriteLine("Line read: " + line);
}
}
我测试了上面的代码,如果你想一次读一行,它就可以工作。唯一的问题是,如果在完成写入之前将该行刷新到文件中,那么您将分多个部分读取该行。只要日志系统一次写入每一行就应该没问题。
如果不是,那么您可能希望读取缓冲区而不是使用 ReadLine,因此您可以通过检测每个 Environment.NewLine 子字符串自己解析缓冲区。
【讨论】:
您可以在一个紧密的循环中继续调用 ReadToEnd()。即使到达文件末尾,它也只会返回一个空字符串“”。如果将更多数据写入文件,它将在后续调用中获取。
while (true)
{
string moreData = streamReader.ReadToEnd();
Thread.Sleep(100);
}
请记住,您可能会以这种方式阅读部分行。此外,如果您正在处理非常大的文件,您可能需要另一种方法。
【讨论】:
使用 filesystemwatcher 检测更改并使用上次读取位置获取新行并查找文件。
http://msdn.microsoft.com/en-us/library/system.io.filestream.seek.aspx
【讨论】:
日志文件正在“持续”更新,因此您真的不应该在每次文件更改时使用FileSystemWatcher 来引发事件。这将持续触发,并且您已经知道它会非常频繁地更改。
我建议使用计时器事件来定期处理文件。 Read this SO answer 获取使用 System.Threading.Timer1 的良好模式。保持文件流打开以供阅读或每次重新打开,Seek 到最后一次成功读取的结束位置。 “最后一次成功读取”是指您应该封装完整日志行的读取和验证。成功读取并验证日志行后,您就有了下一个 Seek 的新位置。
1 请注意,System.Threading.Timer 将在系统提供的线程上执行,该线程由ThreadPool 保持在业务中。对于短任务,这比专用线程更可取。
【讨论】:
在另一个帖子c# continuously read file 上使用这个答案。
这个非常有效,它每秒检查一次文件大小是否发生变化。因此文件通常不会因此而被读锁定。
其他答案非常有效且简单。他们中的一些人会连续读取锁定文件,但这对大多数人来说可能不是问题。
【讨论】: