繁体   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