4

I have a program that continuously writes its log to a text file. I don't have the source code of it, so I can not modify it in any way and it is also protected with Themida.

I need to read the log file and execute some scripts depending on the content of the file. I can not delete the file because the program that is continuously writing to it has locked the file. So what will be the better way to read the file and only read the new lines of the file? Saving the last line position? Or is there something that will be useful for solving it in C#?

4

6 回答 6

6

也许使用FileSystemWatcher以及使用 FileShare 打开文件(因为它正在被另一个进程使用)。Hans Passant在这里为这部分提供了一个很好的答案:

var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); 
        using (var sr = new StreamReader(fs)) {
            // etc...
        } 

看看这个问题和接受的答案,这也可能有所帮助。

于 2013-10-07T16:29:24.530 回答
3

您可以在一个紧密的循环中继续调用 ReadToEnd() 。即使到达文件末尾,它也只会返回一个空字符串“”。如果将更多数据写入文件,它将在后续调用中获取。

while (true)
{
    string moreData = streamReader.ReadToEnd();
    Thread.Sleep(100);
}

请记住,您可能会以这种方式阅读部分行。此外,如果您正在处理非常大的文件,您可能需要另一种方法。

于 2013-10-07T16:44:48.423 回答
3
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 子字符串自己解析缓冲区。

于 2013-10-07T16:29:43.567 回答
2

使用 filesystemwatcher 检测更改并使用上次读取位置获取新行并查找文件。

http://msdn.microsoft.com/en-us/library/system.io.filestream.seek.aspx

于 2013-10-07T17:02:28.047 回答
1

日志文件正在“持续”更新,因此您真的不应该FileSystemWatcher在每次文件更改时引发事件。这将持续触发,并且您已经知道它会非常频繁地变化。

我建议使用计时器事件来定期处理文件。 阅读此 SO 答案以获得使用System.Threading.Timer1的良好模式。保持文件流打开以供阅读或每次重新打开并查找到上次成功读取的结束位置。“最后一次成功读取”是指您应该封装完整日志行的读取和验证。成功阅读并验证日志行后,您就有了下一个Seek.

1请注意,它将在由ThreadPoolSystem.Threading.Timer保持业务的系统提供的线程上执行。对于短任务,这比专用线程更可取。

于 2013-10-07T19:28:41.407 回答
1

在另一篇文章c# 连续读取文件上使用此答案。

这个非常有效,它每秒检查一次文件大小是否已更改。因此,文件通常不会因此而被读锁定。

其他答案非常有效和简单。他们中的一些人会连续读锁定文件,但这对大多数人来说可能不是问题。

于 2017-02-27T23:09:31.977 回答