123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- // ZipFile.Extract.cs
- // ------------------------------------------------------------------
- //
- // Copyright (c) 2009 Dino Chiesa.
- // All rights reserved.
- //
- // This code module is part of DotNetZip, a zipfile class library.
- //
- // ------------------------------------------------------------------
- //
- // This code is licensed under the Microsoft Public License.
- // See the file License.txt for the license details.
- // More info on: http://dotnetzip.codeplex.com
- //
- // ------------------------------------------------------------------
- //
- // last saved (in emacs):
- // Time-stamp: <2011-July-31 14:45:18>
- //
- // ------------------------------------------------------------------
- //
- // This module defines the methods for Extract operations on zip files.
- //
- // ------------------------------------------------------------------
- //
- using System;
- using System.IO;
- using System.Collections.Generic;
- namespace Ionic.Zip
- {
- public partial class ZipFile
- {
- /// <summary>
- /// Extracts all of the items in the zip archive, to the specified path in the
- /// filesystem. The path can be relative or fully-qualified.
- /// </summary>
- ///
- /// <remarks>
- /// <para>
- /// This method will extract all entries in the <c>ZipFile</c> to the
- /// specified path.
- /// </para>
- ///
- /// <para>
- /// If an extraction of a file from the zip archive would overwrite an
- /// existing file in the filesystem, the action taken is dictated by the
- /// ExtractExistingFile property, which overrides any setting you may have
- /// made on individual ZipEntry instances. By default, if you have not
- /// set that property on the <c>ZipFile</c> instance, the entry will not
- /// be extracted, the existing file will not be overwritten and an
- /// exception will be thrown. To change this, set the property, or use the
- /// <see cref="ZipFile.ExtractAll(string,
- /// Ionic.Zip.ExtractExistingFileAction)" /> overload that allows you to
- /// specify an ExtractExistingFileAction parameter.
- /// </para>
- ///
- /// <para>
- /// The action to take when an extract would overwrite an existing file
- /// applies to all entries. If you want to set this on a per-entry basis,
- /// then you must use one of the <see
- /// cref="ZipEntry.Extract()">ZipEntry.Extract</see> methods.
- /// </para>
- ///
- /// <para>
- /// This method will send verbose output messages to the <see
- /// cref="StatusMessageTextWriter"/>, if it is set on the <c>ZipFile</c>
- /// instance.
- /// </para>
- ///
- /// <para>
- /// You may wish to take advantage of the <c>ExtractProgress</c> event.
- /// </para>
- ///
- /// <para>
- /// About timestamps: When extracting a file entry from a zip archive, the
- /// extracted file gets the last modified time of the entry as stored in
- /// the archive. The archive may also store extended file timestamp
- /// information, including last accessed and created times. If these are
- /// present in the <c>ZipEntry</c>, then the extracted file will also get
- /// these times.
- /// </para>
- ///
- /// <para>
- /// A Directory entry is somewhat different. It will get the times as
- /// described for a file entry, but, if there are file entries in the zip
- /// archive that, when extracted, appear in the just-created directory,
- /// then when those file entries are extracted, the last modified and last
- /// accessed times of the directory will change, as a side effect. The
- /// result is that after an extraction of a directory and a number of
- /// files within the directory, the last modified and last accessed
- /// timestamps on the directory will reflect the time that the last file
- /// was extracted into the directory, rather than the time stored in the
- /// zip archive for the directory.
- /// </para>
- ///
- /// <para>
- /// To compensate, when extracting an archive with <c>ExtractAll</c>,
- /// DotNetZip will extract all the file and directory entries as described
- /// above, but it will then make a second pass on the directories, and
- /// reset the times on the directories to reflect what is stored in the
- /// zip archive.
- /// </para>
- ///
- /// <para>
- /// This compensation is performed only within the context of an
- /// <c>ExtractAll</c>. If you call <c>ZipEntry.Extract</c> on a directory
- /// entry, the timestamps on directory in the filesystem will reflect the
- /// times stored in the zip. If you then call <c>ZipEntry.Extract</c> on
- /// a file entry, which is extracted into the directory, the timestamps on
- /// the directory will be updated to the current time.
- /// </para>
- /// </remarks>
- ///
- /// <example>
- /// This example extracts all the entries in a zip archive file, to the
- /// specified target directory. The extraction will overwrite any
- /// existing files silently.
- ///
- /// <code>
- /// String TargetDirectory= "unpack";
- /// using(ZipFile zip= ZipFile.Read(ZipFileToExtract))
- /// {
- /// zip.ExtractExistingFile= ExtractExistingFileAction.OverwriteSilently;
- /// zip.ExtractAll(TargetDirectory);
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Dim TargetDirectory As String = "unpack"
- /// Using zip As ZipFile = ZipFile.Read(ZipFileToExtract)
- /// zip.ExtractExistingFile= ExtractExistingFileAction.OverwriteSilently
- /// zip.ExtractAll(TargetDirectory)
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <seealso cref="Ionic.Zip.ZipFile.ExtractProgress"/>
- /// <seealso cref="Ionic.Zip.ZipFile.ExtractExistingFile"/>
- ///
- /// <param name="path">
- /// The path to which the contents of the zipfile will be extracted.
- /// The path can be relative or fully-qualified.
- /// </param>
- ///
- public void ExtractAll(string path)
- {
- _InternalExtractAll(path, true);
- }
- /// <summary>
- /// Extracts all of the items in the zip archive, to the specified path in the
- /// filesystem, using the specified behavior when extraction would overwrite an
- /// existing file.
- /// </summary>
- ///
- /// <remarks>
- ///
- /// <para>
- /// This method will extract all entries in the <c>ZipFile</c> to the specified
- /// path. For an extraction that would overwrite an existing file, the behavior
- /// is dictated by <paramref name="extractExistingFile"/>, which overrides any
- /// setting you may have made on individual ZipEntry instances.
- /// </para>
- ///
- /// <para>
- /// The action to take when an extract would overwrite an existing file
- /// applies to all entries. If you want to set this on a per-entry basis,
- /// then you must use <see cref="ZipEntry.Extract(String,
- /// ExtractExistingFileAction)" /> or one of the similar methods.
- /// </para>
- ///
- /// <para>
- /// Calling this method is equivalent to setting the <see
- /// cref="ExtractExistingFile"/> property and then calling <see
- /// cref="ExtractAll(String)"/>.
- /// </para>
- ///
- /// <para>
- /// This method will send verbose output messages to the
- /// <see cref="StatusMessageTextWriter"/>, if it is set on the <c>ZipFile</c> instance.
- /// </para>
- /// </remarks>
- ///
- /// <example>
- /// This example extracts all the entries in a zip archive file, to the
- /// specified target directory. It does not overwrite any existing files.
- /// <code>
- /// String TargetDirectory= "c:\\unpack";
- /// using(ZipFile zip= ZipFile.Read(ZipFileToExtract))
- /// {
- /// zip.ExtractAll(TargetDirectory, ExtractExistingFileAction.DontOverwrite);
- /// }
- /// </code>
- ///
- /// <code lang="VB">
- /// Dim TargetDirectory As String = "c:\unpack"
- /// Using zip As ZipFile = ZipFile.Read(ZipFileToExtract)
- /// zip.ExtractAll(TargetDirectory, ExtractExistingFileAction.DontOverwrite)
- /// End Using
- /// </code>
- /// </example>
- ///
- /// <param name="path">
- /// The path to which the contents of the zipfile will be extracted.
- /// The path can be relative or fully-qualified.
- /// </param>
- ///
- /// <param name="extractExistingFile">
- /// The action to take if extraction would overwrite an existing file.
- /// </param>
- /// <seealso cref="ExtractSelectedEntries(String,ExtractExistingFileAction)"/>
- public void ExtractAll(string path, ExtractExistingFileAction extractExistingFile)
- {
- ExtractExistingFile = extractExistingFile;
- _InternalExtractAll(path, true);
- }
- private void _InternalExtractAll(string path, bool overrideExtractExistingProperty)
- {
- bool header = Verbose;
- _inExtractAll = true;
- try
- {
- OnExtractAllStarted(path);
- int n = 0;
- foreach (ZipEntry e in _entries.Values)
- {
- if (header)
- {
- StatusMessageTextWriter.WriteLine("\n{1,-22} {2,-8} {3,4} {4,-8} {0}",
- "Name", "Modified", "Size", "Ratio", "Packed");
- StatusMessageTextWriter.WriteLine(new System.String('-', 72));
- header = false;
- }
- if (Verbose)
- {
- StatusMessageTextWriter.WriteLine("{1,-22} {2,-8} {3,4:F0}% {4,-8} {0}",
- e.FileName,
- e.LastModified.ToString("yyyy-MM-dd HH:mm:ss"),
- e.UncompressedSize,
- e.CompressionRatio,
- e.CompressedSize);
- if (!String.IsNullOrEmpty(e.Comment))
- StatusMessageTextWriter.WriteLine(" Comment: {0}", e.Comment);
- }
- e.Password = _Password; // this may be null
- OnExtractEntry(n, true, e, path);
- if (overrideExtractExistingProperty)
- e.ExtractExistingFile = this.ExtractExistingFile;
- e.Extract(path);
- n++;
- OnExtractEntry(n, false, e, path);
- if (_extractOperationCanceled)
- break;
- }
- if (!_extractOperationCanceled)
- {
- // workitem 8264:
- // now, set times on directory entries, again.
- // The problem is, extracting a file changes the times on the parent
- // directory. So after all files have been extracted, we have to
- // run through the directories again.
- foreach (ZipEntry e in _entries.Values)
- {
- // check if it is a directory
- if ((e.IsDirectory) || (e.FileName.EndsWith("/")))
- {
- string outputFile = (e.FileName.StartsWith("/"))
- ? Path.Combine(path, e.FileName.Substring(1))
- : Path.Combine(path, e.FileName);
- e._SetTimes(outputFile, false);
- }
- }
- OnExtractAllCompleted(path);
- }
- }
- finally
- {
- _inExtractAll = false;
- }
- }
- }
- }
|