我有一个tcp监听器,它监听和写入服务器的数据。我使用BlockingCollection
来存储数据。在这里,我不知道文件何时结束。所以,我的文件流总是打开的。
我的部分代码是:
private static BlockingCollection<string> Buffer = new BlockingCollection<string>();
Process()
{
var consumer = Task.Factory.StartNew(() =>WriteData());
while()
{
string request = await reader.ReadLineAsync();
Buffer.Add(request);
}
}
WriteData()
{
FileStream fStream = new FileStream(filename,FileMode.Append,FileAccess.Write,FileShare.Write, 16392);
foreach(var val in Buffer.GetConsumingEnumerable(token))
{
fStream.Write(Encoding.UTF8.GetBytes(val), 0, val.Length);
fStream.Flush();
}
}
问题是我不能在循环中处理文件流,否则我必须为每一行创建文件流,循环可能永远不会结束。
答案 0 :(得分:0)
如果您使用DataFlow ActionBlock,这在.NET 4.5中会容易得多。 ActionBlock接受并缓冲传入消息,并使用一个或多个任务异步处理它们。
你可以这样写:
public static async Task ProcessFile(string sourceFileName,string targetFileName)
{
//Pass the target stream as part of the message to avoid globals
var block = new ActionBlock<Tuple<string, FileStream>>(async tuple =>
{
var line = tuple.Item1;
var stream = tuple.Item2;
await stream.WriteAsync(Encoding.UTF8.GetBytes(line), 0, line.Length);
});
//Post lines to block
using (var targetStream = new FileStream(targetFileName, FileMode.Append,
FileAccess.Write, FileShare.Write, 16392))
{
using (var sourceStream = File.OpenRead(sourceFileName))
{
await PostLines(sourceStream, targetStream, block);
}
//Tell the block we are done
block.Complete();
//And wait fo it to finish
await block.Completion;
}
}
private static async Task PostLines(FileStream sourceStream, FileStream targetStream,
ActionBlock<Tuple<string, FileStream>> block)
{
using (var reader = new StreamReader(sourceStream))
{
while (true)
{
var line = await reader.ReadLineAsync();
if (line == null)
break;
var tuple = Tuple.Create(line, targetStream);
block.Post(tuple);
}
}
}
大多数代码都处理读取每一行并将其发布到块中。默认情况下,ActionBlock一次只使用一个Task来处理一条消息,这在这种情况下很好。如果需要并行处理数据,可以使用更多任务。
读取所有行后,我们通过调用Complete
通知块,并等待它完成await block.Completion
的处理。
一旦块的Completion
任务完成,我们就可以关闭目标流。
DataFlow库的优点在于您可以将多个块链接在一起,以创建处理步骤的管道。 ActionBlock通常是这种链中的最后一步。库负责将数据从一个块传递到下一个块,并在链中传播完成。
例如,一步可以从日志中读取文件,第二步可以用正则表达式解析它们以查找特定模式(例如错误消息)并传递它们,第三步可以接收错误消息并将它们写入另一个文件。每个步骤都将在不同的线程上执行,每个步骤都会缓冲中间消息。