【问题标题】:Read file changes since the last check without running program constantly in C#自上次检查以来读取文件更改而无需在 C# 中不断运行程序
【发布时间】:2018-02-23 08:46:31
【问题描述】:

我正在尝试创建一个简单的文件监视器,它定期检查日志文件中的更新并处理更新。我尝试使用 FileSystemWatcher,但这需要我的应用程序永远运行。我更多地考虑阅读更改,退出,等待计时器,再次阅读更改。

我创建了一个定期运行的服务来读取文件并获取全部数据。下面是简单的代码。

private void SchedularCallback(object e)
{
    string logFile = ReadFromFile("C:\\test.log");
    this.WriteToFile(logFile);
    this.ScheduleService();
}

WriteToFile 函数将数据写入单独的文件(处理数据,实际处理可能涉及其他任务,如调用 WCF 服务、检查互联网访问等)。每次回调发生时,ReadFromFile 都会读取日志文件。下面是读取文件的代码。

private string ReadFromFile(string path)
{
    try
    {
        string logs = "";
        using (StreamReader reader = new StreamReader(path, true))
        {
            logs = reader.ReadToEnd();
            reader.Close();
        }

        return logs;
    }
    catch (Exception ex)
    {
        WriteToFile("Simple Service Error on: {0} " + ex.Message + ex.StackTrace);

        //Stop the Windows Service.
        using (System.ServiceProcess.ServiceController serviceController = new System.ServiceProcess.ServiceController("SimpleService"))
        {
           serviceController.Stop();
        }
        return "";
    }
}

如您所见,每次回调发生时,此代码都会读取整个文件。由于日志文件最终可能非常大,因此不可能每次都读取和处理整个文件。为了改善这一点,我想到了使用 FileSystemWatcher,但这将使我的服务永远运行并且只是一个真正的性能消耗。相反,如果我可以只读取文件中的更改,它会更快。

我也想过存储流写入器的最后一个偏移量,但这只有在附加数据时才有效。如果有人删除整个日志或更改一两行,最后一个偏移量将不起作用。

在这种情况下,最好的方法是什么。日志文件显然不会不断变化,所以我不需要让我的服务保持运行。我不确定二进制流然后与最后一个二进制流进行比较是否是一个好主意。任何关于可能方法的建议都值得赞赏。基本上就像 git 所做的那样来识别自上次提交以来的更改,这就是我正在寻找的。​​p>

谢谢。

【问题讨论】:

    标签: c# file-handling


    【解决方案1】:

    查看 NTFS 的 USN Journal

    它基本上记录了对 NTFS 磁盘上文件的所有更改。

    以下是一些可能有用的链接:

    1. Creating, Modifying, and Deleting a Change Journal
    2. Fsutil usn
    3. File Path from USN Journal

    【讨论】:

    • 稍后会改进答案,要赶火车!
    • 一路平安! :P
    • 刚刚看了 USN 杂志。听起来是个完美的起点。让我做一些研究并尝试实施它。稍后会接受它作为答案。想要确定,我实际上可以在服务中做到这一点。
    • 好的,它确实有效。使用 USN 日志,我可以获取数据。现在,我只需要弄清楚如何使用 C# 代码运行fsutil usn readdata c:\temp\sample.txt 命令。我认为这是一个不同的问题,应该作为它自己的问题。
    • @RickvanLieshout - 请删除此答案中对外部链接的依赖。您当然可以在答案中添加链接,但链接应该仅用于支持您已在答案中添加的内容。另一种看待这个问题的方式是,如果外部网站更改其链接,您的答案应该仍然有效。
    【解决方案2】:

    这正是FileSystemWatcher 的优势所在。只要是单个文件,资源使用量就会降到最低。

    更新:确实,轮询与侦听 API/内核的更改对于日志之类的东西来说可能有点矫枉过正。搜索日志/日志可能会更好(假设它们已打开)。但在最坏/最可靠的情况下,您可以使用自己的计时器系统来监视文件上的 Size+LastModifiedTime。使用 MD5 校验和也应该没问题/很快。

    然后,如果有更改,您可以使用差异库进行同步。例如diffplex.

    如果您可以在此处测试并稍后对结果进行基准测试。这对我和其他用户都非常有帮助,因为我之前使用FileSystemWatcherEx 实现了类似的功能。

    【讨论】:

    • 正如 OP 所述,“我曾想过使用 FileSystemWatcher,但这将使我的服务永远运行,并且会真正消耗性能。
    • 我尝试使用 FileSystemWatcher。它使服务保持不间断运行,然后为每次击键调用OnChanged 事件。因此,如果我在日志文件中添加Hello,FileSystemWatcher 会调用该事件 6 次。不过,我会研究一下diffplex。这可能就是我想要的。
    • 已检查 diffplex。它适用于已经在内存中的文本。它不适用于文件中的文本。如果有意义的话,我想读取文件中的更改,而不是读取整个文件。
    • 哦,这有点复杂。如果您确定您的文件是文本文件并且只从底部更改,您将自己存储最后一个流位置,然后在有更改的任何时候寻找该位置,并从该位置读取。您当然必须说明何时清除/删除日志。
    猜你喜欢
    • 1970-01-01
    • 2012-04-22
    • 2021-09-26
    • 1970-01-01
    • 1970-01-01
    • 2018-02-06
    • 1970-01-01
    • 1970-01-01
    • 2019-12-24
    相关资源
    最近更新 更多