簡體   English   中英

C#並發文件流讀/寫eof

[英]C# concurrent filestream read/write eof

我有一個線程在日志文件中生成行:

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");
    }
});

讀取器應該讀取所​​有寫入的行,因此它應該等待更多數據,而不是在第一次遇到EOF時停止。 我不介意讀者永遠不會“完成”,只要文件繼續存在,就允許讀者繼續閱讀。 我該如何實現? 用於復制目的的完整代碼:

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);
        }
    }
}

編輯:作為一個實際示例,這對於第三方進程正在生成需要讀取和處理的日志條目的情況很有用。 如果這樣可以使應用程序更清晰地使用,則可以將其視為日志文件讀取器。

您可以在line == null時執行檢查,方法是檢查streamReader.EndOfFile屬性。 使用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");
}

編輯:您可以不使用else塊:

else 
{ 
    while (streamReader.EndOfStream) 
    { 
        Thread.Sleep(1000) 
    } 
}

像這樣:

while (running)
{
    line = streamReader.ReadLine();
    if (line != null)
    {
        Console.WriteLine(line);
    }
}

您需要同步機制,在這種情況下,我將使用AutoResetEvent。 根據您的代碼進行所需的更改。

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.

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