簡體   English   中英

使用blockingcollection進行文件寫入

[英]file writing using blockingcollection

我有一個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();
 }

}

問題是我無法在循環中放置文件流,否則我必須為每一行創建文件流,循環可能永遠不會結束。

如果您使用了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一次僅使用一個任務來處理一條消息,在這種情況下很好。 如果需要並行處理數據,則可以使用更多任務。

讀取所有行后,我們通過調用Complete通知該塊,並等待它通過await block.Completion完成處理。

區塊的Completion任務完成后,我們可以關閉目標流。

DataFlow庫的優點在於,您可以將多個塊鏈接在一起,以創建處理步驟的管道。 ActionBlock通常是此類鏈中的最后一步。 該庫會小心地將數據從一個塊傳遞到下一個塊,並沿鏈向下傳播完成。

例如,一個步驟可以從日志中讀取文件,第二個步驟可以使用正則表達式解析它們以找到特定的模式(例如錯誤消息)並將其傳遞,第三個步驟可以接收錯誤消息並將它們寫入另一個文件。 每個步驟將在不同的線程上執行,並且在每個步驟中緩沖中間消息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM