在C#/ .NET(在Windows上)有没有办法使用文件流读取“增长”文件?打开文件流时文件的长度将非常小,但该文件将由另一个线程写入。如果/当文件流“赶上”到另一个线程时(即当Read()
返回0字节读取时),我想暂停以允许文件缓冲一点,然后继续读取。
我真的不想使用FilesystemWatcher
并继续创建新的文件流(就像日志文件所建议的那样),因为这不是一个日志文件(它是一个即时编码的视频文件)并且表现是一个问题。
谢谢,
罗伯特
答案 0 :(得分:6)
您可以这样做,但您需要使用Stream.Seek
并在线程之间进行适当的同步,仔细跟踪文件的读写位置。通常,您将使用EventWaitHandle
或其子类来执行数据同步,您还需要考虑同步访问FileStream
对象本身(可能通过lock
语句)。
更新:在回答this question时,我实施了类似的操作 - 文件在后台下载并同时上传。我使用了内存缓冲区,并发布了一个gist,它有工作代码。 (这是GPL,但这对你来说可能无关紧要 - 无论如何你都可以使用这些原则来做你自己的事情。)
答案 1 :(得分:4)
我解决这个问题的方法是使用DirectoryWatcher / FilesystemWatcher类,当它在文件上触发时,你需要打开一个FileStream并将其读取到最后。当我完成阅读时,我保存了阅读器的位置,所以下次DirectoryWatcher / FilesystemWatcher触发时我打开一个流,将位置设置为我上次的位置。
调用FileStream.length实际上非常慢,我的解决方案没有性能问题(我正在阅读“日志”,范围从10mb到50 ish)。
对我而言,我描述的解决方案非常简单且易于维护,我会尝试并对其进行分析。我不认为你会在此基础上得到任何性能问题。当ppl正在玩一个多线程游戏时,我这样做,拿走他们的整个CPU,并且没有人抱怨我的解析器比竞争解析器要求更高。
答案 2 :(得分:4)
这适用于文件周围的StreamReader,具有以下步骤:
在写入文件的程序中,使用读取共享打开它,如下所示:
var out = new StreamWriter(File.Open("logFile.txt", FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read));
在读取文件的程序中,使用读写共享打开它,如下所示:
using (FileStream fileStream = File.Open("logFile.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using ( var file = new StreamReader(fileStream))
在访问输入流之前,请检查是否已到达结束,如果是,请等待一段时间。
while (file.EndOfStream)
{
Thread.Sleep(5);
}
答案 3 :(得分:2)
另一件可能有用的事情是FileStream类上有一个名为ReadTimeOut的属性,定义为:
获取或设置一个以毫秒为单位的值,该值确定流在超时之前尝试读取的时间长度。 (继承自Stream)
这可能很有用,因为当您的读取赶上您的写入时,执行读取的线程可能会在写入缓冲区被刷新时暂停。值得编写一个小测试,看看这个属性是否会以任何方式帮助你的事业。
读取和写入操作是否发生在同一个对象上?如果是这样,你可以在文件上编写自己的抽象,然后编写跨线程通信代码,使执行写操作的线程在完成时通知线程执行读操作,以便执行读操作的线程知道何时停止读当它到达EOF时。