16

在 C#/.NET(在 Windows 上)中,有没有一种方法可以使用文件流来读取“正在增长的”文件?打开文件流时文件的长度会非常小,但文件将被另一个线程写入。如果/当文件流“赶上”到另一个线程(即当Read()返回 0 字节读取时),我想暂停以允许文件缓冲一点,然后继续阅读。

我真的不想使用FilesystemWatcher并继续创建新的文件流(如对日志文件的建议),因为这不是日志文件(它是动态编码的视频文件)并且性能是一个问题。

谢谢,
罗伯特

4

4 回答 4

6

Stream.Seek您可以这样做,但您需要使用线程之间的适当同步来仔细跟踪文件读取和写入位置。通常,您将使用其EventWaitHandle子类或子类来进行数据同步,并且您还需要考虑同步以访问FileStream对象本身(可能通过lock语句)。

更新:在回答这个问题时,我实现了类似的东西 - 在后台下载文件并同时上传文件的情况。我使用了内存缓冲区,并发布了一个包含工作代码的要点。(这是 GPL,但这对你来说可能无关紧要——在任何情况下,你都可以使用这些原则来做你自己的事情。)

于 2009-09-11T07:44:15.780 回答
5

这与围绕文件的 StreamReader 一起使用,步骤如下:

  1. 在写入文件的程序中,使用读取共享打开它,如下所示:

    var out = new StreamWriter(File.Open("logFile.txt",  FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read));
    
  2. 在读取文件的程序中,用读写共享打开它,如下所示:

    using (FileStream fileStream = File.Open("logFile.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
    using ( var file = new StreamReader(fileStream))
    
  3. Before accessing the input stream, check whether the end has been reached, and if so, wait around a while.

    while (file.EndOfStream)
    {
        Thread.Sleep(5);
    }
    
于 2012-07-22T00:04:30.033 回答
4

我解决这个问题的方法是使用DirectoryWatcher / FilesystemWatcher 类,当它触发文件时,你希望你打开一个 FileStream 并将其读到最后。当我完成阅读时,我保存了阅读器的位置,所以下次DirectoryWatcher / FilesystemWatcher 触发器我打开一个流时,将位置设置为我上次所在的位置。

调用 FileStream.length 实际上非常慢,我的解决方案没有性能问题(我正在阅读从 10mb 到 50 ish 的“日志”)。

对我来说,我描述的解决方案非常简单且易于维护,我会尝试并对其进行分析。我认为您不会因此而遇到任何性能问题。当人们玩多线程游戏时,我会这样做,占用他们的整个 CPU 并且没有人抱怨我的解析器比竞争的解析器要求更高。

于 2009-09-11T07:43:26.933 回答
2

可能有用的另一件事是 FileStream 类有一个名为 ReadTimeOut 的属性,其定义为:

获取或设置一个值(以毫秒为单位),该值确定流在超时之前尝试读取的时间。(继承自流)

这可能很有用,因为当您的读取赶上您的写入时,执行读取的线程可能会在写入缓冲区被刷新时暂停。确实值得编写一个小测试,看看这个属性是否会以任何方式帮助您的事业。

读写操作是否发生在同一个对象上?如果是这样,您可以在文件上编写自己的抽象,然后编写跨线程通信代码,以便执行写入的线程并在完成时通知执行读取的线程,以便执行读取的线程知道何时停止读取当它到达EOF时。

于 2009-09-11T08:12:29.313 回答