如何保证在多线程中写入文件有异常?

How to guaranteed write into file in multithreading with exceptions?

这是一个简化的例子

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            new Thread(() => Method1()).Start();
            new Thread(() => Method2()).Start();
            Console.Read();
        }

        private static void Method1()
        {
            using (StreamWriter sw = new StreamWriter(@"h:\data.txt"))
            {
                int i = 100000000;
                while (true)
                {
                    Thread.Sleep(100);
                    sw.WriteLine(i);
                    i++;
                }
            }
        }

        private static void Method2()
        {
            Thread.Sleep(6000);
            throw null;
        }
    }
}

如果异常过早发生在另一个线程中,StreamWriter 不会将数据写入文件。发生异常时文件 data.txt 为空。

我试了一下这种情况并找到了一些解决方法:

  1. 如果我增加异常线程的睡眠间隔(并减少写入文件的间隔),文件将充满数据。这不是一个选择,因为我不知道什么时候会出现异常。

  2. 由于之前的解决方法,我可以减小流写入器的缓冲区大小。但是如果我把它设置得太小,它似乎不起作用——例如,这段代码

    FileStream fs = new FileStream(@"h:\data.txt", FileMode.Create);

    使用 (StreamWriter sw = new StreamWriter(fs, Encoding.Default, 10))

不起作用,因为第一次写入操作仅在缓冲区中等待写入文件的大约 385 个整数时发生。

  1. 如果我在异常发生前关闭写入器,文件将被填充。但这不是一个好的选择——我必须每秒写入文件 1 到 10 次。如此频繁地打开和关闭写入器不是一个好主意,是吗?

  2. 我可以像这样捕获异常

    private static void Method2() {

    try
    {
        Thread.Sleep(6000);
        throw null;
    }
    catch
    {
        Console.WriteLine("Exception!");
    }
    

    }

一切都会好起来的——应用程序不会终止,文件会逐包填充。但事实并非如此——我无法控制异常发生的时间和地点。我尝试在所有地方使用 try-catch 但我可能会遗漏一些东西。

所以情况是:StreamWriter的buffer没有满,另外一个线程发生exception,没有被catch,所以应用会被终止。如何不丢失这些数据并将其写入文件?

据我了解您的情况,您假设某处存在错误并且进程可能随时终止。您想尽可能多地保存数据。

您应该可以在 StreamWriter 上呼叫 Flush。这会将数据推送到 OS。如果您的进程终止,数据最终将由 OS.

写入

如果你不能说服 StreamWriter 由于某种原因实际冲洗你可以使用 FileStream 并写入它(伪代码:fileStream.Write(Encoding.GetBytes(myString)))。然后您可以刷新 FileStream 或使用缓冲区大小 1.

当然最好在一开始就阻止进程被终止。这通常直接使用 Task 而不是使用原始 Threads.

Flushing 流将确保其所有内容都被推送到其基础文件中。

这将确保在您完成操作后保存所有数据,并且后续异常不会使您的应用程序丢失数据。