From 467fc2d03dc4f0710761d17e6728c68b73b65d79 Mon Sep 17 00:00:00 2001 From: Anders Gardebring Date: Thu, 20 Apr 2017 11:45:53 +0200 Subject: [PATCH] Add new feature to allow injection of an action into the extraction process. This allows for showing or logging progress of the extraction process, especially useful for large files that might take a long time to extract. --- .../Archives/IArchiveEntryExtensions.cs | 7 ++++--- src/SharpCompress/Readers/AbstractReader.cs | 11 +++++----- src/SharpCompress/Readers/IReader.cs | 3 ++- .../Readers/IReaderExtensions.cs | 21 +++++++++++++------ src/SharpCompress/Utility.cs | 5 ++++- src/SharpCompress/Writers/AbstractWriter.cs | 2 +- src/SharpCompress/Writers/GZip/GZipWriter.cs | 4 ++-- src/SharpCompress/Writers/IWriter.cs | 2 +- src/SharpCompress/Writers/Tar/TarWriter.cs | 8 +++---- src/SharpCompress/Writers/Zip/ZipWriter.cs | 8 +++---- 10 files changed, 42 insertions(+), 29 deletions(-) diff --git a/src/SharpCompress/Archives/IArchiveEntryExtensions.cs b/src/SharpCompress/Archives/IArchiveEntryExtensions.cs index f4f8cb6b..878ad797 100644 --- a/src/SharpCompress/Archives/IArchiveEntryExtensions.cs +++ b/src/SharpCompress/Archives/IArchiveEntryExtensions.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using SharpCompress.Common; using SharpCompress.IO; using SharpCompress.Readers; @@ -7,7 +8,7 @@ namespace SharpCompress.Archives { public static class IArchiveEntryExtensions { - public static void WriteTo(this IArchiveEntry archiveEntry, Stream streamToWriteTo) + public static void WriteTo(this IArchiveEntry archiveEntry, Stream streamToWriteTo, Action partTransferredAction = null) { if (archiveEntry.Archive.Type == ArchiveType.Rar && archiveEntry.Archive.IsSolid) { @@ -32,7 +33,7 @@ namespace SharpCompress.Archives { using (Stream s = new ListeningStream(streamListener, entryStream)) { - s.TransferTo(streamToWriteTo); + s.TransferTo(streamToWriteTo, partTransferredAction); } } streamListener.FireEntryExtractionEnd(archiveEntry); diff --git a/src/SharpCompress/Readers/AbstractReader.cs b/src/SharpCompress/Readers/AbstractReader.cs index 380e8df5..a055c17f 100644 --- a/src/SharpCompress/Readers/AbstractReader.cs +++ b/src/SharpCompress/Readers/AbstractReader.cs @@ -167,7 +167,7 @@ namespace SharpCompress.Readers } } - public void WriteEntryTo(Stream writableStream) + public void WriteEntryTo(Stream writableStream, Action partTransferredAction = null) { if (wroteCurrentEntry) { @@ -175,22 +175,21 @@ namespace SharpCompress.Readers } if ((writableStream == null) || (!writableStream.CanWrite)) { - throw new ArgumentNullException( - "A writable Stream was required. Use Cancel if that was intended."); + throw new ArgumentNullException("A writable Stream was required. Use Cancel if that was intended."); } var streamListener = this as IReaderExtractionListener; streamListener.FireEntryExtractionBegin(Entry); - Write(writableStream); + Write(writableStream, partTransferredAction); streamListener.FireEntryExtractionEnd(Entry); wroteCurrentEntry = true; } - internal void Write(Stream writeStream) + internal void Write(Stream writeStream, Action partTransferredAction = null) { using (Stream s = OpenEntryStream()) { - s.TransferTo(writeStream); + s.TransferTo(writeStream, partTransferredAction); } } diff --git a/src/SharpCompress/Readers/IReader.cs b/src/SharpCompress/Readers/IReader.cs index 0df03177..6b1a7818 100644 --- a/src/SharpCompress/Readers/IReader.cs +++ b/src/SharpCompress/Readers/IReader.cs @@ -20,7 +20,8 @@ namespace SharpCompress.Readers /// Decompresses the current entry to the stream. This cannot be called twice for the current entry. /// /// - void WriteEntryTo(Stream writableStream); + /// + void WriteEntryTo(Stream writableStream, Action partTransferredAction = null); bool Cancelled { get; } void Cancel(); diff --git a/src/SharpCompress/Readers/IReaderExtensions.cs b/src/SharpCompress/Readers/IReaderExtensions.cs index 4100a607..2fdeb1d9 100644 --- a/src/SharpCompress/Readers/IReaderExtensions.cs +++ b/src/SharpCompress/Readers/IReaderExtensions.cs @@ -1,4 +1,5 @@ #if !NO_FILE +using System; using System.IO; using SharpCompress.Common; #endif @@ -39,8 +40,12 @@ namespace SharpCompress.Readers /// /// Extract to specific directory, retaining filename /// - public static void WriteEntryToDirectory(this IReader reader, string destinationDirectory, - ExtractionOptions options = null) + public static void WriteEntryToDirectory( + this IReader reader, + string destinationDirectory, + ExtractionOptions options = null, + Action partTransferredAction = null + ) { string destinationFileName = string.Empty; string file = Path.GetFileName(reader.Entry.Key); @@ -66,7 +71,7 @@ namespace SharpCompress.Readers if (!reader.Entry.IsDirectory) { - reader.WriteEntryToFile(destinationFileName, options); + reader.WriteEntryToFile(destinationFileName, options, partTransferredAction); } else if (options.ExtractFullPath && !Directory.Exists(destinationFileName)) { @@ -77,8 +82,12 @@ namespace SharpCompress.Readers /// /// Extract to specific file /// - public static void WriteEntryToFile(this IReader reader, string destinationFileName, - ExtractionOptions options = null) + public static void WriteEntryToFile( + this IReader reader, + string destinationFileName, + ExtractionOptions options = null, + Action partTransferredAction = null + ) { FileMode fm = FileMode.Create; options = options ?? new ExtractionOptions() @@ -92,7 +101,7 @@ namespace SharpCompress.Readers } using (FileStream fs = File.Open(destinationFileName, fm)) { - reader.WriteEntryTo(fs); + reader.WriteEntryTo(fs, partTransferredAction); //using (Stream s = reader.OpenEntryStream()) //{ // s.TransferTo(fs); diff --git a/src/SharpCompress/Utility.cs b/src/SharpCompress/Utility.cs index 451075f3..253e0e9d 100644 --- a/src/SharpCompress/Utility.cs +++ b/src/SharpCompress/Utility.cs @@ -229,15 +229,18 @@ namespace SharpCompress return DosDateToDateTime((UInt32)iTime); } - public static long TransferTo(this Stream source, Stream destination) + public static long TransferTo(this Stream source, Stream destination, Action partTransferredAction = null) { byte[] array = new byte[81920]; int count; + var iterations = 0; long total = 0; while ((count = source.Read(array, 0, array.Length)) != 0) { total += count; destination.Write(array, 0, count); + iterations++; + partTransferredAction?.Invoke(total, iterations); } return total; } diff --git a/src/SharpCompress/Writers/AbstractWriter.cs b/src/SharpCompress/Writers/AbstractWriter.cs index dde6892a..79f880b9 100644 --- a/src/SharpCompress/Writers/AbstractWriter.cs +++ b/src/SharpCompress/Writers/AbstractWriter.cs @@ -24,7 +24,7 @@ namespace SharpCompress.Writers public ArchiveType WriterType { get; } - public abstract void Write(string filename, Stream source, DateTime? modificationTime); + public abstract void Write(string filename, Stream source, DateTime? modificationTime, Action partTransferredAction = null); protected virtual void Dispose(bool isDisposing) { diff --git a/src/SharpCompress/Writers/GZip/GZipWriter.cs b/src/SharpCompress/Writers/GZip/GZipWriter.cs index d9ef3562..48b88a29 100644 --- a/src/SharpCompress/Writers/GZip/GZipWriter.cs +++ b/src/SharpCompress/Writers/GZip/GZipWriter.cs @@ -26,7 +26,7 @@ namespace SharpCompress.Writers.GZip base.Dispose(isDisposing); } - public override void Write(string filename, Stream source, DateTime? modificationTime) + public override void Write(string filename, Stream source, DateTime? modificationTime, Action partTransferredAction = null) { if (wroteToStream) { @@ -35,7 +35,7 @@ namespace SharpCompress.Writers.GZip GZipStream stream = OutputStream as GZipStream; stream.FileName = filename; stream.LastModified = modificationTime; - source.TransferTo(stream); + source.TransferTo(stream, partTransferredAction); wroteToStream = true; } } diff --git a/src/SharpCompress/Writers/IWriter.cs b/src/SharpCompress/Writers/IWriter.cs index a15225bf..d55e8b74 100644 --- a/src/SharpCompress/Writers/IWriter.cs +++ b/src/SharpCompress/Writers/IWriter.cs @@ -7,6 +7,6 @@ namespace SharpCompress.Writers public interface IWriter : IDisposable { ArchiveType WriterType { get; } - void Write(string filename, Stream source, DateTime? modificationTime); + void Write(string filename, Stream source, DateTime? modificationTime, Action partTransferredAction = null); } } \ No newline at end of file diff --git a/src/SharpCompress/Writers/Tar/TarWriter.cs b/src/SharpCompress/Writers/Tar/TarWriter.cs index 0dbdb0a2..552b0c93 100644 --- a/src/SharpCompress/Writers/Tar/TarWriter.cs +++ b/src/SharpCompress/Writers/Tar/TarWriter.cs @@ -39,9 +39,9 @@ namespace SharpCompress.Writers.Tar InitalizeStream(destination, !options.LeaveStreamOpen); } - public override void Write(string filename, Stream source, DateTime? modificationTime) + public override void Write(string filename, Stream source, DateTime? modificationTime, Action partTransferredAction = null) { - Write(filename, source, modificationTime, null); + Write(filename, source, modificationTime, null, partTransferredAction); } private string NormalizeFilename(string filename) @@ -57,7 +57,7 @@ namespace SharpCompress.Writers.Tar return filename.Trim('/'); } - public void Write(string filename, Stream source, DateTime? modificationTime, long? size) + public void Write(string filename, Stream source, DateTime? modificationTime, long? size, Action partTransferredAction = null) { if (!source.CanSeek && size == null) { @@ -71,7 +71,7 @@ namespace SharpCompress.Writers.Tar header.Name = NormalizeFilename(filename); header.Size = realSize; header.Write(OutputStream); - size = source.TransferTo(OutputStream); + size = source.TransferTo(OutputStream, partTransferredAction); PadTo512(size.Value, false); } diff --git a/src/SharpCompress/Writers/Zip/ZipWriter.cs b/src/SharpCompress/Writers/Zip/ZipWriter.cs index e1a001b5..96efa0b6 100644 --- a/src/SharpCompress/Writers/Zip/ZipWriter.cs +++ b/src/SharpCompress/Writers/Zip/ZipWriter.cs @@ -90,19 +90,19 @@ namespace SharpCompress.Writers.Zip } } - public override void Write(string entryPath, Stream source, DateTime? modificationTime) + public override void Write(string entryPath, Stream source, DateTime? modificationTime, Action partTransferredAction = null) { Write(entryPath, source, new ZipWriterEntryOptions() { ModificationDateTime = modificationTime - }); + }, partTransferredAction); } - public void Write(string entryPath, Stream source, ZipWriterEntryOptions zipWriterEntryOptions) + public void Write(string entryPath, Stream source, ZipWriterEntryOptions zipWriterEntryOptions, Action partTransferredAction = null) { using (Stream output = WriteToStream(entryPath, zipWriterEntryOptions)) { - source.TransferTo(output); + source.TransferTo(output, partTransferredAction); } }