using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; using System.IO.Compression; namespace CommonLibrary { internal class ProgressStream : Stream { private readonly Stream insideStream; private readonly IProgress insideReadProgress; private readonly IProgress insideWriteProgress; public ProgressStream(Stream stream, IProgress readProgress, IProgress writeProgress) { insideStream = stream; insideReadProgress = readProgress; insideWriteProgress = writeProgress; } public override bool CanRead { get { return insideStream.CanRead; } } public override bool CanSeek { get { return insideStream.CanSeek; } } public override bool CanWrite { get { return insideStream.CanWrite; } } public override long Length { get { return insideStream.Length; } } public override long Position { get { return insideStream.Position; } set { insideStream.Position = value; } } public override void Flush() { insideStream.Flush(); } public override long Seek(long offset, SeekOrigin origin) { return insideStream.Seek(offset, origin); } public override void SetLength(long value) { insideStream.SetLength(value); } public override int Read(byte[] buffer, int offset, int count) { int bytesRead = insideStream.Read(buffer, offset, count); insideReadProgress?.Report(bytesRead); return bytesRead; } public override void Write(byte[] buffer, int offset, int count) { insideStream.Write(buffer, offset, count); insideWriteProgress?.Report(count); } } public class ProgressPacker { public void Pack(string sourceDirectoryName, string packFileName, IProgress progress) { sourceDirectoryName = Path.GetFullPath(sourceDirectoryName); FileInfo[] sourceFiles = new DirectoryInfo(sourceDirectoryName).GetFiles("*", SearchOption.AllDirectories); double totalBytes = sourceFiles.Sum(f => f.Length); long currentBytes = 0; using (ZipArchive zipArchive = ZipFile.Open(packFileName, ZipArchiveMode.Create)) { foreach (FileInfo file in sourceFiles) { string entryName = file.FullName.Substring(sourceDirectoryName.Length + 1); ZipArchiveEntry entry = zipArchive.CreateEntry(entryName); entry.LastWriteTime = file.LastWriteTime; using (Stream inputStream = file.OpenRead()) { using (Stream outputStream = entry.Open()) { Stream progressStream = new ProgressStream(inputStream, new BasicProgress(i => { currentBytes += i; progress.Report(currentBytes / totalBytes); }), null); progressStream.CopyTo(outputStream); } } } } } public void UnPack(string packFileName, string destinationDirectoryName, IProgress progress) { using (ZipArchive zipArchive = ZipFile.OpenRead(packFileName)) { double totalBytes = zipArchive.Entries.Sum(f => f.Length); long currentBytes = 0; foreach (ZipArchiveEntry entry in zipArchive.Entries) { string fileName = Path.Combine(destinationDirectoryName, entry.FullName); if (entry.Name == "") continue; Directory.CreateDirectory(Path.GetDirectoryName(fileName)); using (Stream inputStream = entry.Open()) { using (Stream outputStream = File.OpenWrite(fileName)) { Stream progressStream = new ProgressStream(outputStream, null, new BasicProgress(i => { currentBytes += i; if (progress != null) { progress.Report(currentBytes / totalBytes); } })); inputStream.CopyTo(progressStream); } File.SetLastWriteTime(fileName, entry.LastWriteTime.LocalDateTime); } } } } } public class BasicProgress : IProgress { private readonly Action actionHandler; public BasicProgress(Action handler) { actionHandler = handler; } void IProgress.Report(T value) { actionHandler(value); } } }