В этой статье поговорим об еще одной популярной библиотеке для работы с архивами – DotNetZip. На данный момент это
самая популярная библиотека для работы с архивами. О популярности этой
библиотеки можно судить по количеству скачиваний. На момент написания статьи их было
больше 172 тысяч, чем DotNetZip немного опережает своего ближайшего конкурента SharpZipLib.
Для удобства работы с этой библиотекой создадим класс-обертку, которая будет выполнять за нас всю "грязную работу", а
мы для этого ей передадим лишь несколько параметров. Основную работу мы
возложим на созданный нами класс IonicZipHelper.
Ниже приведена реализация этого класса.
public class IonicZipHelper
{
public void CompressionDirectory(string fileName,
string sourceDirectory,
CompressionLevel compressionLevel = CompressionLevel.Default)
{
using (var zipFile = new ZipFile(fileName))
{
zipFile.CompressionLevel =
compressionLevel;
zipFile.AddDirectory(sourceDirectory, "\\");
zipFile.Save();
}
}
public void AppendFilesToZip(string fileName,
List<string> appendFiles,
CompressionLevel compressionLevel = CompressionLevel.Default)
{
using (var zipFile = ZipFile.Read(fileName))
{
zipFile.CompressionLevel =
compressionLevel;
zipFile.AddFiles(appendFiles, "\\");
zipFile.Save();
}
}
public void AppendFilesToZipFromArray(string fileName,
List<byte[]> appendFiles,
CompressionLevel compressionLevel = CompressionLevel.Default)
{
using (var zipFile = new ZipFile(fileName))
{
zipFile.CompressionLevel =
compressionLevel;
foreach (var file in appendFiles)
{
var tempFileName = Guid.NewGuid().ToString();
zipFile.AddEntry(tempFileName,
file);
}
zipFile.Save();
}
}
public void ExtractZip(string fileName, string outFolder)
{
using (var zip = ZipFile.Read(fileName))
{
foreach (var e in zip)
{
e.Extract(outFolder, ExtractExistingFileAction.OverwriteSilently);
}
}
}
}
Как видите,
для написания класса-обертки над данной библиотекой нужно совсем мало
кода. Для того, чтобы начать ее использовать, достаточно минимальных знаний языка C#. Мне не
приходилось видеть библиотеки проще, чем данная. Перейдем к
тестам данной библиотеки, чтобы посмотреть, как она справляется с поставленной
задачей.
Класс для
измерения тестов приведен ниже.
public static class Profiler
{
public static double MeasureAction(Action action)
{
var st = new Stopwatch();
st.Start();
action();
st.Stop();
return st.Elapsed.TotalMilliseconds;
}
}
Исходный
код использования библиотеки Ionic.Zip:
static void Main(string[] args)
{
//Compress
directory
var directory =
CreateEmptyDirectory();
var zipHelper = new IonicZipHelper();
var resultFile = Path.Combine(Directory.GetCurrentDirectory(), "result.txt");
if (File.Exists(resultFile))
File.Delete(resultFile);
var sourceDirecory = @"D:\CSharp\IocContainersDemo";
//var
sourceDirecory = @"D:\books\Introduction to F#";
var size =
GetDirectorySize(sourceDirecory);
File.AppendAllText(resultFile, string.Format("Directory
size {0}
bytes {1}", size, Environment.NewLine));
var ionicZlibPacking = "IonicZlibPacking.zip";
string fileName = Path.Combine(directory,
ionicZlibPacking);
var result = Profiler.MeasureAction(() =>
zipHelper.CompressionDirectory(fileName,
sourceDirecory));
File.AppendAllText(resultFile, string.Format("Zip
directory with ZipFile {0} msec, Size: {1}{2}",
result,
new FileInfo(fileName).Length,
Environment.NewLine));
//Add
all compression
var compressFiles = new List<Tuple<string, Ionic.Zlib.CompressionLevel>>(new[]
{
new Tuple<string, Ionic.Zlib.CompressionLevel>(Path.Combine(directory, "Test1.zip"), Ionic.Zlib.CompressionLevel.None),
new Tuple<string, Ionic.Zlib.CompressionLevel>(Path.Combine(directory, "Test2.zip"), Ionic.Zlib.CompressionLevel.BestSpeed),
new Tuple<string, Ionic.Zlib.CompressionLevel>(Path.Combine(directory, "Test3.zip"), Ionic.Zlib.CompressionLevel.Level2),
new Tuple<string, Ionic.Zlib.CompressionLevel>(Path.Combine(directory, "Test4.zip"), Ionic.Zlib.CompressionLevel.Level3),
new Tuple<string, Ionic.Zlib.CompressionLevel>(Path.Combine(directory, "Test5.zip"), Ionic.Zlib.CompressionLevel.Level4),
new Tuple<string, Ionic.Zlib.CompressionLevel>(Path.Combine(directory, "Test6.zip"), Ionic.Zlib.CompressionLevel.Level5),
new Tuple<string, Ionic.Zlib.CompressionLevel>(Path.Combine(directory, "Test7.zip"), Ionic.Zlib.CompressionLevel.Default),
new Tuple<string, Ionic.Zlib.CompressionLevel>(Path.Combine(directory, "Test8.zip"), Ionic.Zlib.CompressionLevel.Level7),
new Tuple<string, Ionic.Zlib.CompressionLevel>(Path.Combine(directory, "Test9.zip"), Ionic.Zlib.CompressionLevel.Level8),
new Tuple<string, Ionic.Zlib.CompressionLevel>(Path.Combine(directory, "Test10.zip"), Ionic.Zlib.CompressionLevel.BestCompression),
});
foreach (var compressFile in compressFiles)
{
//Avoid closure variable
var temp = compressFile;
var res = Profiler.MeasureAction(() =>
zipHelper.CompressionDirectory(temp.Item1,
sourceDirecory,
temp.Item2));
File.AppendAllText(resultFile, string.Format("Zip
directory with ZipFile {0} msec, Size: {1}{2}",
res,
new FileInfo(temp.Item1).Length,
Environment.NewLine));
}
//Add
file to existing archive
var tempFileOne = Path.Combine(directory, Guid.NewGuid().ToString());
var tempFileTwo = Path.Combine(directory, Guid.NewGuid().ToString());
File.AppendAllText(tempFileOne, "test1");
File.AppendAllText(tempFileTwo, "test2");
zipHelper.AppendFilesToZip(fileName,
new List<string>(new [] { tempFileOne, tempFileTwo}));
//Add
byte[] arrays to archive
var tempArchive = Path.Combine(directory, "TempArchive.zip");
var array1 = Encoding.UTF8.GetBytes("Test1");
var array2 = Encoding.UTF8.GetBytes("Test2");
zipHelper.AppendFilesToZipFromArray(tempArchive,
new List<byte[]>(new List<byte[]> { array1, array2}));
//Read
from archive
var outputDirectory = Path.Combine(directory, "12345");
if (!Directory.Exists(outputDirectory))
Directory.CreateDirectory(outputDirectory);
var outputResult = Profiler.MeasureAction(() =>
zipHelper.ExtractZip(fileName, outputDirectory));
File.AppendAllText(resultFile, string.Format("Unzip file
to directory {0}
msec, FileName: {1}{2}",
outputResult,
fileName,
Environment.NewLine));
DeleteTempDirectory();
}
private static void DeleteTempDirectory()
{
var directory = Path.Combine(Directory.GetCurrentDirectory(), "TestArchives");
if (Directory.Exists(directory))
Directory.Delete(directory, true);
}
private static string CreateEmptyDirectory()
{
var directory = Path.Combine(Directory.GetCurrentDirectory(), "TestArchives");
if (!Directory.Exists(directory))
Directory.CreateDirectory(directory);
else
{
var files = Directory.GetFiles(directory);
foreach (var file in files)
{
File.Delete(file);
}
}
return directory;
}
static long GetDirectorySize(string path)
{
var a = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
return a.Select(name => new FileInfo(name)).Select(info =>
info.Length).Sum();
}
Интересный момент,
что код для упаковки и распаковки
архива, добавления файлов в существующий архив, добавления байтовых данных в
архив, получился больше, чем наш класс-враппер над данной библиотекой. Этот результат не
может не радовать. J
Работу с архивом я
условно разделил на 5 частей:
1) создание zip архива
с сжатием по умолчанию;
2) создание zip-архивов с разной доступной
степенью сжатия данных;
3) добавление файлов в
уже существующий архив;
4) добавление байтовых
данных в архив без промежуточного сохранения;
5) извлечение данных с
архива.
Эти все пункты подписаны
комментариями в коде и не нуждаются в дополнительном пояснении ввиду своей простоты.
Ниже приведен результат
второго теста. Тест создан не искусственно, за основу взяты реальные данные.
В тесте, приведенном выше, взят файл проекта с библиотеками. Тест, приведенный ниже,
архивирует видеоуроки по языку F#.
Итоги
В этой статье мы рассмотрели использование библиотеки DotNetZip. Эта библиотека на данный момент является самой популярной для архивирования. Она проста в использовании и имеет широкие
возможности. Она удобнее в использовании, по сравнению с другой популярной библиотекой
SharpZipLib.
Для того чтобы использовать DotNetZip,
нужно написать меньше кода, чем для SharpZipLib. Попробуйте добавить
файл в уже существующий архив, и Вы сразу поймете, что я имел ввиду под
удобством. Надеюсь, использование этой библиотеки поможет Вам легко справляться с задачами
архивирования.
No comments:
Post a Comment