这是一个简化的例子
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为空。
我对这种情况稍微玩了一下,发现了一堆解决方法:
如果我增加异常线程的休眠间隔(并减少写入文件之间的间隔),文件将填充数据。这不是一个选择,因为我不知道何时发生异常。
由于之前的解决方法,我可以减少流编写器的缓冲区大小。但是如果我把它设置得太小似乎没有用 - 例如,这段代码
FileStream fs = new FileStream(@“h:\ data.txt”,FileMode.Create);
使用(StreamWriter sw = new StreamWriter(fs,Encoding.Default,10))
不起作用,因为只有当大约385个整数在缓冲区中等待写入文件时才会发生第一次写操作。
如果在异常发生之前关闭编写器,将填写文件。但这不是一个好选择 - 我必须每秒写入1到10次文件。如此频繁地打开和关闭作者不是一个好主意,是吗?
我可以像这样抓住异常
private static void Method2() {
try
{
Thread.Sleep(6000);
throw null;
}
catch
{
Console.WriteLine("Exception!");
}
}
一切都会好 - 没有应用程序终止和文件将逐包填写。但事实并非如此 - 我无法控制异常发生的时间和地点。我尝试在任何地方使用try-catch,但我可能会错过一些东西。
所以情况是:StreamWriter的缓冲区未满,在另一个线程中发生异常并且未被捕获,因此应用程序将被终止。如何不丢失这些数据并将其写入文件?
答案 0 :(得分:2)
根据我了解您的情况,您假设某处存在错误,并且该过程可能随时终止。您希望尽可能多地保存数据。
您应该可以在Flush
上致电StreamWriter
。这会将数据推送到操作系统。如果您的进程终止,则数据最终将由操作系统写入。
如果您因某种原因无法说服StreamWriter
实际刷新,可以使用FileStream
并写入(伪代码:fileStream.Write(Encoding.GetBytes(myString))
)。然后,您可以刷新FileStream
或使用1的缓冲区大小。
当然,如果您阻止该流程首先被终止,那么它是最好的。与使用原始Task
相反,Thread
通常是直截了当的。
答案 1 :(得分:1)
Flushing流将确保将其所有内容都推送到其底层文件中。
这样可以确保在完成操作后保存所有数据,并且以下异常不会使您的应用程序丢失数据。