2009-09-11 47 views
16

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

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

感谢,
罗伯特

+0

我更新了我的答案。 – 2009-09-11 08:10:37

回答

6

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

更新:在回答this question我实现了类似的东西 - 一个文件在后台下载并同时上传的情况。我用内存缓冲区,并发布了一个gist其中有工作代码。 (这是GPL,但对你来说可能并不重要 - 无论如何你可以使用这些原则来做你自己的事情。)

+0

我会研究这个...对于踢腿,将编码结果写入内存(例如使用双缓冲区),然后将它同时发送到网络和缓存文件可能更容易吗? – 2009-09-11 07:53:22

4

我解决了这个使用DirectoryWatcher/FileSystemWatcher类,而当它触发的文件你想打开一个FileStream并读到尾的方式。当我完成阅读时,我保存了阅读器的位置,所以下次启动时,我打开一个流,将位置设置为我上次所在的位置。

调用FileStream.length实际上非常慢,我没有性能问题与我的解决方案(我正在读一个“日志”范围从10MB到50伊西)。

对我而言,我所描述的解决方案非常简单,易于维护,我会尝试并对其进行配置。我不认为你会基于它得到任何性能问题。当我玩这个多线程游戏时,我会这样做,并且不会有人抱怨我的解析器对竞争解析器的要求更高。

+1

由于性能方面的考虑,该问题使用观察者特别打折。 – 2009-09-11 07:45:32

+0

是的,我注意到了。在关于性能的回复中增加了更多内容。 – EKS 2009-09-11 07:46:04

+0

如果您所做的只是尽可能读取,然后等待更多数据,则您不一定必须在读取器中调用FileStream.Length。你看到的观察者触发有什么样的延迟?这是否会根据机器负载而改变? – 2009-09-11 07:49:44

2

另一个可能有用的东西是FileStream类有一个名为ReadTimeOut的属性,它是定义为:

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

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

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

+0

如果在FileStream上设置ReadTimeOut会引发异常,该如何得到+3? :S – 2015-12-24 22:50:13

4

这大约有文件一个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. 访问输入流之前,请检查是否已到达输入流,如果有,请稍等片刻。

    while (file.EndOfStream) 
    { 
        Thread.Sleep(5); 
    }