2013-03-27 60 views
0

我压缩日志文件数据写入到它,像:碰撞安全上的即时压缩与GZipStream

using (var fs = new FileStream("Test.gz", FileMode.Create, FileAccess.Write, FileShare.None)) 
{ 
    using (var compress = new GZipStream(fs, CompressionMode.Compress)) 
    { 
    for (int i = 0; i < 1000000; i++) 
    { 
     // Clearly this isn't what is happening in production, just 
     // a simply example 
     byte[] message = RandomBytes(); 
     compress.Write(message, 0, message.Length); 

     // Flush to disk (in production we will do this every x lines, 
     // or x milliseconds, whichever comes first) 
     if (i % 20 == 0) 
     { 
     compress.Flush(); 
     } 
    } 
    } 
} 

我想要确保的是,如果该进程崩溃或死亡,档案仍然有效和可读。我曾希望自上次冲洗以来的任何事情都是安全的,但我只是以腐败归档而告终。

有没有什么方法可以确保每次刷新后我都会得到一个可读的归档文件?

注:我们使用GZipStream并不重要,如果别的东西会给我们想要的结果。

+0

为什么不以全胖模式写出文件,并且一旦它们在磁盘上就按计划批量压缩?这将是一大堆更安全。 – spender 2013-03-27 11:26:07

+0

因为我们想要保持磁盘利用率低。但是,如果进程死亡,我们也希望最大化可读数据量 – Cocowalla 2013-03-27 11:30:55

+0

我也不确定如果我们能够批量压缩 - 文件每分钟滚动一次,但每个文件可以高达500MB左右没有压缩 – Cocowalla 2013-03-27 11:33:26

回答

2

一个选项是让Windows处理压缩。只需在要存储日志文件的文件夹上启用压缩。有一些performance considerations你应该知道复制压缩文件时,我不知道NT压缩与GZipStream或其他压缩选项比较表现如何。您可能想要比较压缩比和CPU负载。

如果您不想在整个文件夹上启用压缩,还可以选择打开压缩文件。我没有试过这个,但你可能想看看它:http://social.msdn.microsoft.com/forums/en-US/netfxbcl/thread/1b63b4a4-b197-4286-8f3f-af2498e3afe5

+0

真的很有趣的方式来看待它,并感谢额外的信息(特别是关于性能的考虑) – Cocowalla 2013-03-27 14:28:05

+0

接受这个答案,因为它让我控制数据刷新到磁盘的确切时间,并确保文件在进程崩溃时可读(无需运行任何修复工具) – Cocowalla 2013-03-29 15:03:06

1

好消息:GZip是一种流式格式。因此,流末尾的腐败不会影响已写入的开头。

因此,即使您的流式写入在任意点处被中断,大部分流仍然很好。你可以自己写一个小工具读取它,并在它看到的第一个异常处停下来。

如果你想要一个无错的解决方案,我建议每隔x秒将日志分成一个文件(也许x = 1或10?)。写入扩展名为“.gz.tmp”的文件,并在文件完全写入并关闭后重命名为“.gz”。

+0

我们已经每分钟分割一次日志文件一次,我需要更多地关注你提出的'错误恢复' – Cocowalla 2013-03-27 14:10:06

+0

Aha ,我使用'gunzip < Test.gz > Test.recovered.txt'对损坏的档案进行了一些测试(确认过程被终止后),并确实能够恢复大部分数据。 – Cocowalla 2013-03-27 14:35:42

0

是的,但它不仅仅是冲水。看看zlib分布中的gzlog.hgzlog.c。它完全符合你的要求,有效地将短日志条目添加到gzip文件,并始终保留有效的gzip文件。它还具有防止进程中崩溃或关闭的功能,仍然保留有效的gzip文件,并且不会丢失任何日志条目。

我建议不要使用GZIPStream。它是越野车,并没有提供必要的功能。改为使用DotNetZip作为zlib的界面。

+0

我刚刚尝试过DotNetZip,并获得与GZIPStream完全相同的结果。它使用的CPU少一点,但这是唯一的区别。顺便说一下,我在.NET 4.5上,我相信GZIPStream现在实际上使用了引擎盖下的zlib库! – Cocowalla 2013-03-27 15:39:49

+0

是的,.NET 4.5至少修复了这个问题。但是接口比DotNetZip更有限。 – 2013-03-27 15:58:21