Быстрое сжатие на лету с помощью 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, если что-то еще даст нам желаемый результат.
3 ответа
Один из вариантов - позволить Windows обрабатывать сжатие. Просто включите сжатие в папке, где вы храните свои файлы журналов. При копировании сжатых файлов следует учитывать некоторые соображения производительности, и я не знаю, насколько хорошо сжатие NT выполняется по сравнению с GZipStream
или другие варианты сжатия. Возможно, вы захотите сравнить коэффициенты сжатия и загрузку процессора.
Также есть возможность открыть сжатый файл, если вы не хотите включать сжатие для всей папки. Я не пробовал это, но вы можете посмотреть это: http://social.msdn.microsoft.com/forums/en-US/netfxbcl/thread/1b63b4a4-b197-4286-8f3f-af2498e3afe5
Хорошие новости: GZip - это потоковый формат. Поэтому повреждение в конце потока не может повлиять на начало, которое уже было записано.
Таким образом, даже если ваши потоковые записи прерываются в произвольной точке, большая часть потока все еще хороша. Вы можете написать себе небольшой инструмент, который читает из него и останавливается при первом обнаруженном исключении.
Если вы хотите безошибочное решение, я бы рекомендовал разбивать журнал на один файл каждые x секунд (возможно, x = 1 или 10?). Запишите в файл с расширениями ".gz.tmp" и переименуйте в ".gz" после того, как файл был полностью написан и закрыт.
Да, но это больше, чем просто промывка. Посмотрите на gzlog.h и gzlog.c в дистрибутиве zlib. Он делает именно то, что вам нужно, эффективно добавляя короткие записи журнала в файл gzip и всегда оставляя действительный файл gzip позади. Он также имеет защиту от сбоев или остановок во время процесса, все еще оставляя действительный файл gzip и не теряя записей журнала.
Я рекомендую не использовать GZIPStream. Он глючит и не обеспечивает необходимой функциональности. Вместо этого используйте DotNetZip в качестве интерфейса для zlib.