/// <summary> /// Create a ZipOutputStream that writes to a filesystem file. /// </summary> /// /// <remarks> /// The <see cref="ZipFile"/> class is generally easier to use when creating /// zip files. The ZipOutputStream offers a different metaphor for creating a /// zip file, based on the <see cref="System.IO.Stream"/> class. /// </remarks> /// /// <param name="fileName"> /// The name of the zip file to create. /// </param> /// /// <example> /// /// This example shows how to create a zip file, using the /// ZipOutputStream class. /// /// <code lang="C#"> /// private void Zipup() /// { /// if (filesToZip.Count == 0) /// { /// System.Console.WriteLine("Nothing to do."); /// return; /// } /// /// using (var output= new ZipOutputStream(outputFileName)) /// { /// output.Password = "******"; /// output.Encryption = EncryptionAlgorithm.WinZipAes256; /// /// foreach (string inputFileName in filesToZip) /// { /// System.Console.WriteLine("file: {0}", inputFileName); /// /// output.PutNextEntry(inputFileName); /// using (var input = File.Open(inputFileName, FileMode.Open, FileAccess.Read, /// FileShare.Read | FileShare.Write )) /// { /// byte[] buffer= new byte[2048]; /// int n; /// while ((n= input.Read(buffer,0,buffer.Length)) > 0) /// { /// output.Write(buffer,0,n); /// } /// } /// } /// } /// } /// </code> /// /// <code lang="VB"> /// Private Sub Zipup() /// Dim outputFileName As String = "XmlData.zip" /// Dim filesToZip As String() = Directory.GetFiles(".", "*.xml") /// If (filesToZip.Length = 0) Then /// Console.WriteLine("Nothing to do.") /// Else /// Using output As ZipOutputStream = New ZipOutputStream(outputFileName) /// output.Password = "******" /// output.Encryption = EncryptionAlgorithm.WinZipAes256 /// Dim inputFileName As String /// For Each inputFileName In filesToZip /// Console.WriteLine("file: {0}", inputFileName) /// output.PutNextEntry(inputFileName) /// Using input As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) /// Dim n As Integer /// Dim buffer As Byte() = New Byte(2048) {} /// Do While (n = input.Read(buffer, 0, buffer.Length) > 0) /// output.Write(buffer, 0, n) /// Loop /// End Using /// Next /// End Using /// End If /// End Sub /// </code> /// </example> internal static ZipOutputStream Create(String fileName) { string fullPath = ZipFileExtensions.GetFullPath(fileName); var file = FileSystem.Current.GetFileFromPathAsync(fullPath).ExecuteSync(); if (file == null) { var dirName = Path.GetDirectoryName(fullPath); var dir = ZipEntryExtensions.CreateDirectory(dirName, true); file = dir.CreateFileAsync(Path.GetFileName(fileName), CreationCollisionOption.ReplaceExisting).ExecuteSync(); } var stream = file.OpenAsync(FileAccess.ReadAndWrite).ExecuteSync(); return(new ZipOutputStream(stream)); }
/// <summary> /// Save the file to a new zipfile, with the given name. /// </summary> /// /// <remarks> /// <para> /// This method allows the application to explicitly specify the name of the zip /// file when saving. Use this when creating a new zip file, or when /// updating a zip archive. /// </para> /// /// <para> /// An application can also save a zip archive in several places by calling this /// method multiple times in succession, with different filenames. /// </para> /// /// <para> /// The <c>ZipFile</c> instance is written to storage, typically a zip file in a /// filesystem, only when the caller calls <c>Save</c>. The Save operation writes /// the zip content to a temporary file, and then renames the temporary file /// to the desired name. If necessary, this method will delete a pre-existing file /// before the rename. /// </para> /// /// </remarks> /// /// <exception cref="System.ArgumentException"> /// Thrown if you specify a directory for the filename. /// </exception> /// /// <param name="fileName"> /// The name of the zip archive to save to. Existing files will /// be overwritten with great prejudice. /// </param> /// /// <example> /// This example shows how to create and Save a zip file. /// <code> /// using (ZipFile zip = new ZipFile()) /// { /// zip.AddDirectory(@"c:\reports\January"); /// zip.Save("January.zip"); /// } /// </code> /// /// <code lang="VB"> /// Using zip As New ZipFile() /// zip.AddDirectory("c:\reports\January") /// zip.Save("January.zip") /// End Using /// </code> /// /// </example> /// /// <example> /// This example shows how to update a zip file. /// <code> /// using (ZipFile zip = ZipFile.Read("ExistingArchive.zip")) /// { /// zip.AddFile("NewData.csv"); /// zip.Save("UpdatedArchive.zip"); /// } /// </code> /// /// <code lang="VB"> /// Using zip As ZipFile = ZipFile.Read("ExistingArchive.zip") /// zip.AddFile("NewData.csv") /// zip.Save("UpdatedArchive.zip") /// End Using /// </code> /// /// </example> public static void Save(this ZipFile zipFile, String fileName) { if (fileName == null) { throw new ArgumentNullException("fileName"); } string fullPath = GetFullPath(fileName); if (FileSystem.Current.GetFolderFromPathAsync(fullPath).ExecuteSync() != null) { throw new ZipException("Bad Directory", new ArgumentException("That name specifies an existing directory. Please specify a filename.", "fileName")); } var fullDirectoryName = Path.GetDirectoryName(fullPath); var directoryName = Path.GetDirectoryName(fileName); var folder = FileSystem.Current.GetFolderFromPathAsync(fullDirectoryName).ExecuteSync(); if (folder == null) { throw new ZipException("Bad Directory", new ArgumentException(string.Format("That folder ({0}) does not exist!", directoryName))); } // check up here so we may shortcut some IO operations in the future :) var fileExists = folder.CheckExistsAsync(fullPath).ExecuteSync() == ExistenceCheckResult.FileExists; // write to a temporary file so that we can read from the same zip when saving var tmpName = Path.GetRandomFileName(); try { ZipSegmentedStreamManager segmentsManager = null; if (zipFile.MaxOutputSegmentSize != 0) { // save segmented files using the segments manager var manager = new FileSystemZipSegmentedStreamManager(fullPath); segmentsManager = manager; zipFile.Save(segmentsManager); tmpName = manager.TemporaryName; } else { // save var tmpFile = folder.CreateFileAsync(tmpName, CreationCollisionOption.ReplaceExisting).ExecuteSync(); tmpName = tmpFile.Path; using (var tmpStream = tmpFile.OpenAsync(FileAccess.ReadAndWrite).ExecuteSync()) { zipFile.Save(tmpStream); } } // if it wasn't canceled if (!zipFile.IsSaveOperationCanceled()) { // disconnect from the stream zipFile.SetUnderlyingZipStream(null); // move the temporary file into position zipFile.OnSaveEvent(ZipProgressEventType.Saving_BeforeRenameTempArchive); ZipEntryExtensions.MoveFileInPlace(fileExists, fullPath, tmpName); zipFile.OnSaveEvent(ZipProgressEventType.Saving_AfterRenameTempArchive); // and now set the read stream to be that of the new file var targetFile = FileSystem.Current.GetFileFromPathAsync(fullPath).ExecuteSync(); var fileStream = targetFile.OpenAsync(FileAccess.Read).ExecuteSync(); zipFile.SetUnderlyingZipSegmentedStreamManager(segmentsManager); zipFile.SetUnderlyingZipStream(fileStream); zipFile.SetShouldDisposeReadStream(true); zipFile.Name = fullPath; // so we can shortcut the existance checks tmpName = null; } } finally { // An exception has occurred. If the file exists, check // to see if it existed before we tried extracting. If // it did not, attempt to remove the target file. There // is a small possibility that the existing file has // been extracted successfully, overwriting a previously // existing file, and an exception was thrown after that // but before final completion (setting times, etc). In // that case the file will remain, even though some // error occurred. Nothing to be done about it. if (tmpName != null) { var tmpFile = folder.GetFileAsync(tmpName).ExecuteSync(); tmpFile.DeleteAsync(); } } }