[英]C# concurrent filestream read/write eof
I have a thread producing lines in a log file: 我有一个线程在日志文件中生成行:
var t1 = Task.Factory.StartNew(() =>
{
using (var fileStream = File.Open(file, FileMode.Create, FileAccess.Write, FileShare.Read))
using (var streamWriter = new StreamWriter(fileStream))
{
for (var i = 0; i < 10; i++)
{
streamWriter.WriteLine(i);
streamWriter.Flush();
Thread.Sleep(1000);
}
}
File.Delete(file);
});
And I have a thread reading lines from the same log file: 我有一个线程从同一个日志文件中读取行:
// Reads lines from the log file.
var t2 = Task.Factory.StartNew(() =>
{
Thread.Sleep(500); // Horrible wait to ensure file existence in this test case.
using (var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.Read | FileShare.Write))
using (var streamReader = new StreamReader(fileStream))
{
string line;
while ((line = streamReader.ReadLine()) != null) Console.WriteLine(line);
// FIXME: The stream reader stops, instead of doing a continous read.
Console.WriteLine("End of file");
}
});
The reader is supposed to read all written lines, therefore it should wait for more data instead of stopping at the first time it encounters EOF. 读取器应该读取所有写入的行,因此它应该等待更多数据,而不是在第一次遇到EOF时停止。 I do not mind if the reader is never 'finished', so long as the file continues to exist, the reader is allowed to continue reading. 我不介意读者永远不会“完成”,只要文件继续存在,就允许读者继续阅读。 How can I achieve this? 我该如何实现? Full code for reproduction purposes: 用于复制目的的完整代码:
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace PlayGround
{
internal static class Program
{
private static void Main()
{
const string file = "test.log";
// Writes lines to the log file.
var t1 = Task.Factory.StartNew(() =>
{
using (var fileStream = File.Open(file, FileMode.Create, FileAccess.Write, FileShare.Read))
using (var streamWriter = new StreamWriter(fileStream))
{
for (var i = 0; i < 10; i++)
{
streamWriter.WriteLine(i);
streamWriter.Flush();
Thread.Sleep(1000);
}
}
File.Delete(file);
});
// Reads lines from the log file.
var t2 = Task.Factory.StartNew(() =>
{
Thread.Sleep(500); // Horrible wait to ensure file existence in this test case.
using (
var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read,
FileShare.Delete | FileShare.Read | FileShare.Write))
using (var streamReader = new StreamReader(fileStream))
{
string line;
while ((line = streamReader.ReadLine()) != null) Console.WriteLine(line);
// FIXME: The stream reader stops, instead of doing a continous read.
Console.WriteLine("End of file");
}
});
Task.WaitAll(t1, t2);
}
}
}
EDIT: As a practical example, this is useful for a scenario where a third party process is producing log entries which need to be read and processed. 编辑:作为一个实际示例,这对于第三方进程正在生成需要读取和处理的日志条目的情况很有用。 You could see this as a log file reader if that makes the application and use clearer. 如果这样可以使应用程序更清晰地使用,则可以将其视为日志文件读取器。
You could perform a wait when the line == null
, by checking the streamReader.EndOfFile
property. 您可以在line == null
时执行检查,方法是检查streamReader.EndOfFile
属性。 Using Thread.Sleep(1000)
is not an ideal solution, a bit hacky, and I guess there are other better alternative solutions out there. 使用Thread.Sleep(1000)
并不是一个理想的解决方案,有点怪异,我想还有其他更好的替代解决方案。 :-) :-)
using (var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.Read | FileShare.Write))
using (var streamReader = new StreamReader(fileStream))
{
string line;
bool running = true; // we may want to terminate this loop in some condition.
while (running)
{
line = streamReader.ReadLine();
if (line != null)
{
Console.WriteLine(line);
}
else // as per edit, the whole else block can be omitted.
{
while (streamReader.EndOfStream)
{
Thread.Sleep(1000); // wait around for n time. This could end up in an infinte loop if the file is not written to anymore.
}
}
}
// FIXME: The stream reader stops, instead of doing a continous read.
Console.WriteLine("End of file");
}
EDIT: You can do without the else block: 编辑:您可以不使用else块:
else
{
while (streamReader.EndOfStream)
{
Thread.Sleep(1000)
}
}
Like this: 像这样:
while (running)
{
line = streamReader.ReadLine();
if (line != null)
{
Console.WriteLine(line);
}
}
You need synchronization mechanism, in this case I use AutoResetEvent. 您需要同步机制,在这种情况下,我将使用AutoResetEvent。 The required changes based on your code is. 根据您的代码进行所需的更改。
const string file = "test.log";
// Adds new line.
AutoResetEvent signal = new AutoResetEvent(false);
streamWriter.Flush();
// Adds new line.
signal.Set();
File.Delete(file);
// Adds new line
signal.Set();
Thread.Sleep(500);
// Replaces with.
signal.WaitOne();
while ((line = streamReader.ReadLine()) != null) Console.WriteLine(line);
// Replaces with.
while ((line = streamReader.ReadLine()) != null)
{
signal.WaitOne();
Console.WriteLine(line);
}
const string file = "test.log";
AutoResetEvent signal = new AutoResetEvent(false);
// Writes lines to the log file.
var t1 = Task.Factory.StartNew(() =>
{
using (var fileStream = File.Open(file, FileMode.Create, FileAccess.Write, FileShare.Read))
{
using (var streamWriter = new StreamWriter(fileStream))
{
for (var i = 0; i < 10; i++)
{
streamWriter.WriteLine(i);
streamWriter.Flush();
signal.Set();
Thread.Sleep(10);
}
}
}
File.Delete(file);
signal.Set();
});
// Reads lines from the log file.
var t2 = Task.Factory.StartNew(() =>
{
signal.WaitOne();
using (var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.Read | FileShare.Write))
{
using (var streamReader = new StreamReader(fileStream))
{
string line;
while ((line = streamReader.ReadLine()) != null)
{
signal.WaitOne();
Console.WriteLine(line);
}
// FIXME: The stream reader stops, instead of doing a continous read.
Console.WriteLine("End of file");
}
}
});
Task.WaitAll(t1, t2);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.