using System; using FileCompression.Interfaces; using System.IO; using System.IO.Compression; using System.Collections.Generic; using FileCompression.Utils; namespace FileCompression.Services.Strategies; public class ZipStrategy : ICompressionStrategy { public void CompressFile(string sourcePath, string destinationPath, string basePath) { Console.WriteLine($"Compressing file {sourcePath} to {destinationPath}"); using (Stream destination = new FileStream(destinationPath, FileMode.OpenOrCreate, FileAccess.ReadWrite)) { using ZipArchive archive = new ZipArchive(destination, ZipArchiveMode.Update); string entryName = ArchiveUtils.EntryFromPath(sourcePath.AsSpan(basePath.Length)); DoCreateEntryFromFile(archive, sourcePath, entryName, CompressionLevel.Optimal); } } public void CompressDirectory(string sourcePath, string destinationPath, string basePath) { Console.WriteLine($"Compressing directory {sourcePath} to {destinationPath}"); using (Stream destination = new FileStream(destinationPath, FileMode.OpenOrCreate, FileAccess.ReadWrite)) { using ZipArchive archive = new ZipArchive(destination, ZipArchiveMode.Update); string entryName = ArchiveUtils.EntryFromPath(sourcePath.AsSpan(basePath.Length), appendPathSeparator: true); archive.CreateEntry(entryName); } } private ZipArchiveEntry DoCreateEntryFromFile(ZipArchive destination, string sourceFileName, string entryName, CompressionLevel? compressionLevel) { ArgumentNullException.ThrowIfNull(destination); ArgumentNullException.ThrowIfNull(sourceFileName); ArgumentNullException.ThrowIfNull(entryName); // Checking of compressionLevel is passed down to DeflateStream and the IDeflater implementation // as it is a pluggable component that completely encapsulates the meaning of compressionLevel. // Argument checking gets passed down to FileStream's ctor and CreateEntry using (FileStream fs = new FileStream(sourceFileName, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 0x1000, useAsync: false)) { ZipArchiveEntry entry = compressionLevel.HasValue ? destination.CreateEntry(entryName, compressionLevel.Value) : destination.CreateEntry(entryName); DateTime lastWrite = File.GetLastWriteTime(sourceFileName); // If file to be archived has an invalid last modified time, use the first datetime representable in the Zip timestamp format // (midnight on January 1, 1980): if (lastWrite.Year < 1980 || lastWrite.Year > 2107) lastWrite = new DateTime(1980, 1, 1, 0, 0, 0); entry.LastWriteTime = lastWrite; using (Stream es = entry.Open()) fs.CopyTo(es); return entry; } } }