// ZipFile.AddUpdate.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009-2011 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-November-01 13:56:58>
//
// ------------------------------------------------------------------
//
// This module defines the methods for Adding and Updating entries in
// the ZipFile.
//
// ------------------------------------------------------------------
//
using System;
using System.IO;
using System.Collections.Generic;
namespace OfficeOpenXml.Packaging.Ionic.Zip
{
internal partial class ZipFile
{
///
/// Adds an item, either a file or a directory, to a zip file archive.
///
///
///
///
/// This method is handy if you are adding things to zip archive and don't
/// want to bother distinguishing between directories or files. Any files are
/// added as single entries. A directory added through this method is added
/// recursively: all files and subdirectories contained within the directory
/// are added to the ZipFile.
///
///
///
/// The name of the item may be a relative path or a fully-qualified
/// path. Remember, the items contained in ZipFile instance get written
/// to the disk only when you call or a similar
/// save method.
///
///
///
/// The directory name used for the file within the archive is the same
/// as the directory name (potentially a relative path) specified in the
/// .
///
///
///
/// For ZipFile properties including , , , , ,
/// , and , their
/// respective values at the time of this call will be applied to the
/// ZipEntry added.
///
///
///
///
///
///
///
///
/// This method has two overloads.
///
/// the name of the file or directory to add.
///
/// The ZipEntry added.
public ZipEntry AddItem(string fileOrDirectoryName)
{
return AddItem(fileOrDirectoryName, null);
}
///
/// Adds an item, either a file or a directory, to a zip file archive,
/// explicitly specifying the directory path to be used in the archive.
///
///
///
///
/// If adding a directory, the add is recursive on all files and
/// subdirectories contained within it.
///
///
/// The name of the item may be a relative path or a fully-qualified path.
/// The item added by this call to the ZipFile is not read from the
/// disk nor written to the zip file archive until the application calls
/// Save() on the ZipFile.
///
///
///
/// This version of the method allows the caller to explicitly specify the
/// directory path to be used in the archive, which would override the
/// "natural" path of the filesystem file.
///
///
///
/// Encryption will be used on the file data if the Password has
/// been set on the ZipFile object, prior to calling this method.
///
///
///
/// For ZipFile properties including , , , , ,
/// , and , their
/// respective values at the time of this call will be applied to the
/// ZipEntry added.
///
///
///
///
///
/// Thrown if the file or directory passed in does not exist.
///
///
/// the name of the file or directory to add.
///
///
///
/// The name of the directory path to use within the zip archive. This path
/// need not refer to an extant directory in the current filesystem. If the
/// files within the zip are later extracted, this is the path used for the
/// extracted file. Passing null (Nothing in VB) will use the
/// path on the fileOrDirectoryName. Passing the empty string ("") will
/// insert the item at the root path within the archive.
///
///
///
///
///
///
///
/// This example shows how to zip up a set of files into a flat hierarchy,
/// regardless of where in the filesystem the files originated. The resulting
/// zip archive will contain a toplevel directory named "flat", which itself
/// will contain files Readme.txt, MyProposal.docx, and Image1.jpg. A
/// subdirectory under "flat" called SupportFiles will contain all the files
/// in the "c:\SupportFiles" directory on disk.
///
///
/// String[] itemnames= {
/// "c:\\fixedContent\\Readme.txt",
/// "MyProposal.docx",
/// "c:\\SupportFiles", // a directory
/// "images\\Image1.jpg"
/// };
///
/// try
/// {
/// using (ZipFile zip = new ZipFile())
/// {
/// for (int i = 1; i < itemnames.Length; i++)
/// {
/// // will add Files or Dirs, recurses and flattens subdirectories
/// zip.AddItem(itemnames[i],"flat");
/// }
/// zip.Save(ZipToCreate);
/// }
/// }
/// catch (System.Exception ex1)
/// {
/// System.Console.Error.WriteLine("exception: {0}", ex1);
/// }
///
///
///
/// Dim itemnames As String() = _
/// New String() { "c:\fixedContent\Readme.txt", _
/// "MyProposal.docx", _
/// "SupportFiles", _
/// "images\Image1.jpg" }
/// Try
/// Using zip As New ZipFile
/// Dim i As Integer
/// For i = 1 To itemnames.Length - 1
/// ' will add Files or Dirs, recursing and flattening subdirectories.
/// zip.AddItem(itemnames(i), "flat")
/// Next i
/// zip.Save(ZipToCreate)
/// End Using
/// Catch ex1 As Exception
/// Console.Error.WriteLine("exception: {0}", ex1.ToString())
/// End Try
///
///
/// The ZipEntry added.
public ZipEntry AddItem(String fileOrDirectoryName, String directoryPathInArchive)
{
if (File.Exists(fileOrDirectoryName))
return AddFile(fileOrDirectoryName, directoryPathInArchive);
if (Directory.Exists(fileOrDirectoryName))
return AddDirectory(fileOrDirectoryName, directoryPathInArchive);
throw new FileNotFoundException(String.Format("That file or directory ({0}) does not exist!",
fileOrDirectoryName));
}
///
/// Adds a File to a Zip file archive.
///
///
///
///
/// This call collects metadata for the named file in the filesystem,
/// including the file attributes and the timestamp, and inserts that metadata
/// into the resulting ZipEntry. Only when the application calls Save() on
/// the ZipFile, does DotNetZip read the file from the filesystem and
/// then write the content to the zip file archive.
///
///
///
/// This method will throw an exception if an entry with the same name already
/// exists in the ZipFile.
///
///
///
/// For ZipFile properties including , , , , ,
/// , and , their
/// respective values at the time of this call will be applied to the
/// ZipEntry added.
///
///
///
///
///
///
/// In this example, three files are added to a Zip archive. The ReadMe.txt
/// file will be placed in the root of the archive. The .png file will be
/// placed in a folder within the zip called photos\personal. The pdf file
/// will be included into a folder within the zip called Desktop.
///
///
/// try
/// {
/// using (ZipFile zip = new ZipFile())
/// {
/// zip.AddFile("c:\\photos\\personal\\7440-N49th.png");
/// zip.AddFile("c:\\Desktop\\2008-Regional-Sales-Report.pdf");
/// zip.AddFile("ReadMe.txt");
///
/// zip.Save("Package.zip");
/// }
/// }
/// catch (System.Exception ex1)
/// {
/// System.Console.Error.WriteLine("exception: " + ex1);
/// }
///
///
///
/// Try
/// Using zip As ZipFile = New ZipFile
/// zip.AddFile("c:\photos\personal\7440-N49th.png")
/// zip.AddFile("c:\Desktop\2008-Regional-Sales-Report.pdf")
/// zip.AddFile("ReadMe.txt")
/// zip.Save("Package.zip")
/// End Using
/// Catch ex1 As Exception
/// Console.Error.WriteLine("exception: {0}", ex1.ToString)
/// End Try
///
///
///
/// This method has two overloads.
///
///
///
///
///
///
/// The name of the file to add. It should refer to a file in the filesystem.
/// The name of the file may be a relative path or a fully-qualified path.
///
/// The ZipEntry corresponding to the File added.
public ZipEntry AddFile(string fileName)
{
return AddFile(fileName, null);
}
///
/// Adds a File to a Zip file archive, potentially overriding the path to be
/// used within the zip archive.
///
///
///
///
/// The file added by this call to the ZipFile is not written to the
/// zip file archive until the application calls Save() on the ZipFile.
///
///
///
/// This method will throw an exception if an entry with the same name already
/// exists in the ZipFile.
///
///
///
/// This version of the method allows the caller to explicitly specify the
/// directory path to be used in the archive.
///
///
///
/// For ZipFile properties including , , , , ,
/// , and , their
/// respective values at the time of this call will be applied to the
/// ZipEntry added.
///
///
///
///
///
///
/// In this example, three files are added to a Zip archive. The ReadMe.txt
/// file will be placed in the root of the archive. The .png file will be
/// placed in a folder within the zip called images. The pdf file will be
/// included into a folder within the zip called files\docs, and will be
/// encrypted with the given password.
///
///
/// try
/// {
/// using (ZipFile zip = new ZipFile())
/// {
/// // the following entry will be inserted at the root in the archive.
/// zip.AddFile("c:\\datafiles\\ReadMe.txt", "");
/// // this image file will be inserted into the "images" directory in the archive.
/// zip.AddFile("c:\\photos\\personal\\7440-N49th.png", "images");
/// // the following will result in a password-protected file called
/// // files\\docs\\2008-Regional-Sales-Report.pdf in the archive.
/// zip.Password = "EncryptMe!";
/// zip.AddFile("c:\\Desktop\\2008-Regional-Sales-Report.pdf", "files\\docs");
/// zip.Save("Archive.zip");
/// }
/// }
/// catch (System.Exception ex1)
/// {
/// System.Console.Error.WriteLine("exception: {0}", ex1);
/// }
///
///
///
/// Try
/// Using zip As ZipFile = New ZipFile
/// ' the following entry will be inserted at the root in the archive.
/// zip.AddFile("c:\datafiles\ReadMe.txt", "")
/// ' this image file will be inserted into the "images" directory in the archive.
/// zip.AddFile("c:\photos\personal\7440-N49th.png", "images")
/// ' the following will result in a password-protected file called
/// ' files\\docs\\2008-Regional-Sales-Report.pdf in the archive.
/// zip.Password = "EncryptMe!"
/// zip.AddFile("c:\Desktop\2008-Regional-Sales-Report.pdf", "files\documents")
/// zip.Save("Archive.zip")
/// End Using
/// Catch ex1 As Exception
/// Console.Error.WriteLine("exception: {0}", ex1)
/// End Try
///
///
///
///
///
///
///
///
/// The name of the file to add. The name of the file may be a relative path
/// or a fully-qualified path.
///
///
///
/// Specifies a directory path to use to override any path in the fileName.
/// This path may, or may not, correspond to a real directory in the current
/// filesystem. If the files within the zip are later extracted, this is the
/// path used for the extracted file. Passing null (Nothing in
/// VB) will use the path on the fileName, if any. Passing the empty string
/// ("") will insert the item at the root path within the archive.
///
///
/// The ZipEntry corresponding to the file added.
public ZipEntry AddFile(string fileName, String directoryPathInArchive)
{
string nameInArchive = ZipEntry.NameInArchive(fileName, directoryPathInArchive);
ZipEntry ze = ZipEntry.CreateFromFile(fileName, nameInArchive);
if (Verbose) StatusMessageTextWriter.WriteLine("adding {0}...", fileName);
return _InternalAddEntry(ze);
}
///
/// This method removes a collection of entries from the ZipFile.
///
///
///
/// A collection of ZipEntry instances from this zip file to be removed. For
/// example, you can pass in an array of ZipEntry instances; or you can call
/// SelectEntries(), and then add or remove entries from that
/// ICollection<ZipEntry> (ICollection(Of ZipEntry) in VB), and pass
/// that ICollection to this method.
///
///
///
///
public void RemoveEntries(System.Collections.Generic.ICollection entriesToRemove)
{
if (entriesToRemove == null)
throw new ArgumentNullException("entriesToRemove");
foreach (ZipEntry e in entriesToRemove)
{
this.RemoveEntry(e);
}
}
///
/// This method removes a collection of entries from the ZipFile, by name.
///
///
///
/// A collection of strings that refer to names of entries to be removed
/// from the ZipFile. For example, you can pass in an array or a
/// List of Strings that provide the names of entries to be removed.
///
///
///
///
public void RemoveEntries(System.Collections.Generic.ICollection entriesToRemove)
{
if (entriesToRemove == null)
throw new ArgumentNullException("entriesToRemove");
foreach (String e in entriesToRemove)
{
this.RemoveEntry(e);
}
}
///
/// This method adds a set of files to the ZipFile.
///
///
///
///
/// Use this method to add a set of files to the zip archive, in one call.
/// For example, a list of files received from
/// System.IO.Directory.GetFiles() can be added to a zip archive in one
/// call.
///
///
///
/// For ZipFile properties including , , , , ,
/// , and , their
/// respective values at the time of this call will be applied to each
/// ZipEntry added.
///
///
///
///
/// The collection of names of the files to add. Each string should refer to a
/// file in the filesystem. The name of the file may be a relative path or a
/// fully-qualified path.
///
///
///
/// This example shows how to create a zip file, and add a few files into it.
///
/// String ZipFileToCreate = "archive1.zip";
/// String DirectoryToZip = "c:\\reports";
/// using (ZipFile zip = new ZipFile())
/// {
/// // Store all files found in the top level directory, into the zip archive.
/// String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip);
/// zip.AddFiles(filenames);
/// zip.Save(ZipFileToCreate);
/// }
///
///
///
/// Dim ZipFileToCreate As String = "archive1.zip"
/// Dim DirectoryToZip As String = "c:\reports"
/// Using zip As ZipFile = New ZipFile
/// ' Store all files found in the top level directory, into the zip archive.
/// Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip)
/// zip.AddFiles(filenames)
/// zip.Save(ZipFileToCreate)
/// End Using
///
///
///
///
public void AddFiles(System.Collections.Generic.IEnumerable fileNames)
{
this.AddFiles(fileNames, null);
}
///
/// Adds or updates a set of files in the ZipFile.
///
///
///
///
/// Any files that already exist in the archive are updated. Any files that
/// don't yet exist in the archive are added.
///
///
///
/// For ZipFile properties including , , , , ,
/// , and , their
/// respective values at the time of this call will be applied to each
/// ZipEntry added.
///
///
///
///
/// The collection of names of the files to update. Each string should refer to a file in
/// the filesystem. The name of the file may be a relative path or a fully-qualified path.
///
///
public void UpdateFiles(System.Collections.Generic.IEnumerable fileNames)
{
this.UpdateFiles(fileNames, null);
}
///
/// Adds a set of files to the ZipFile, using the
/// specified directory path in the archive.
///
///
///
///
/// Any directory structure that may be present in the
/// filenames contained in the list is "flattened" in the
/// archive. Each file in the list is added to the archive in
/// the specified top-level directory.
///
///
///
/// For ZipFile properties including , , , , , , and , their respective values at the
/// time of this call will be applied to each ZipEntry added.
///
///
///
///
/// The names of the files to add. Each string should refer to
/// a file in the filesystem. The name of the file may be a
/// relative path or a fully-qualified path.
///
///
///
/// Specifies a directory path to use to override any path in the file name.
/// Th is path may, or may not, correspond to a real directory in the current
/// filesystem. If the files within the zip are later extracted, this is the
/// path used for the extracted file. Passing null (Nothing in
/// VB) will use the path on each of the fileNames, if any. Passing
/// the empty string ("") will insert the item at the root path within the
/// archive.
///
///
///
public void AddFiles(System.Collections.Generic.IEnumerable fileNames, String directoryPathInArchive)
{
AddFiles(fileNames, false, directoryPathInArchive);
}
///
/// Adds a set of files to the ZipFile, using the specified directory
/// path in the archive, and preserving the full directory structure in the
/// filenames.
///
///
///
///
///
/// Think of the as a "root" or
/// base directory used in the archive for the files that get added. when
/// is true, the hierarchy of files
/// found in the filesystem will be placed, with the hierarchy intact,
/// starting at that root in the archive. When preserveDirHierarchy
/// is false, the path hierarchy of files is flattned, and the flattened
/// set of files gets placed in the root within the archive as specified in
/// directoryPathInArchive.
///
///
///
/// For ZipFile properties including , , , , ,
/// , and , their
/// respective values at the time of this call will be applied to each
/// ZipEntry added.
///
///
///
///
///
/// The names of the files to add. Each string should refer to a file in the
/// filesystem. The name of the file may be a relative path or a
/// fully-qualified path.
///
///
///
/// Specifies a directory path to use as a prefix for each entry name.
/// This path may, or may not, correspond to a real directory in the current
/// filesystem. If the files within the zip are later extracted, this is the
/// path used for the extracted file. Passing null (Nothing in
/// VB) will use the path on each of the fileNames, if any. Passing
/// the empty string ("") will insert the item at the root path within the
/// archive.
///
///
///
/// whether the entries in the zip archive will reflect the directory
/// hierarchy that is present in the various filenames. For example, if
/// includes two paths,
/// \Animalia\Chordata\Mammalia\Info.txt and
/// \Plantae\Magnoliophyta\Dicotyledon\Info.txt, then calling this method
/// with = false will
/// result in an exception because of a duplicate entry name, while
/// calling this method with =
/// true will result in the full direcory paths being included in
/// the entries added to the ZipFile.
///
///
public void AddFiles(System.Collections.Generic.IEnumerable fileNames,
bool preserveDirHierarchy,
String directoryPathInArchive)
{
if (fileNames == null)
throw new ArgumentNullException("fileNames");
_addOperationCanceled = false;
OnAddStarted();
if (preserveDirHierarchy)
{
foreach (var f in fileNames)
{
if (_addOperationCanceled) break;
if (directoryPathInArchive != null)
{
//string s = SharedUtilities.NormalizePath(Path.Combine(directoryPathInArchive, Path.GetDirectoryName(f)));
string s = Path.GetFullPath(Path.Combine(directoryPathInArchive, Path.GetDirectoryName(f)));
this.AddFile(f, s);
}
else
this.AddFile(f, null);
}
}
else
{
foreach (var f in fileNames)
{
if (_addOperationCanceled) break;
this.AddFile(f, directoryPathInArchive);
}
}
if (!_addOperationCanceled)
OnAddCompleted();
}
///
/// Adds or updates a set of files to the ZipFile, using the specified
/// directory path in the archive.
///
///
///
///
///
/// Any files that already exist in the archive are updated. Any files that
/// don't yet exist in the archive are added.
///
///
///
/// For ZipFile properties including , , , , ,
/// , and , their
/// respective values at the time of this call will be applied to each
/// ZipEntry added.
///
///
///
///
/// The names of the files to add or update. Each string should refer to a
/// file in the filesystem. The name of the file may be a relative path or a
/// fully-qualified path.
///
///
///
/// Specifies a directory path to use to override any path in the file name.
/// This path may, or may not, correspond to a real directory in the current
/// filesystem. If the files within the zip are later extracted, this is the
/// path used for the extracted file. Passing null (Nothing in
/// VB) will use the path on each of the fileNames, if any. Passing
/// the empty string ("") will insert the item at the root path within the
/// archive.
///
///
///
public void UpdateFiles(System.Collections.Generic.IEnumerable fileNames, String directoryPathInArchive)
{
if (fileNames == null)
throw new ArgumentNullException("fileNames");
OnAddStarted();
foreach (var f in fileNames)
this.UpdateFile(f, directoryPathInArchive);
OnAddCompleted();
}
///
/// Adds or Updates a File in a Zip file archive.
///
///
///
///
/// This method adds a file to a zip archive, or, if the file already exists
/// in the zip archive, this method Updates the content of that given filename
/// in the zip archive. The UpdateFile method might more accurately be
/// called "AddOrUpdateFile".
///
///
///
/// Upon success, there is no way for the application to learn whether the file
/// was added versus updated.
///
///
///
/// For ZipFile properties including , , , , ,
/// , and , their
/// respective values at the time of this call will be applied to the
/// ZipEntry added.
///
///
///
///
///
/// This example shows how to Update an existing entry in a zipfile. The first
/// call to UpdateFile adds the file to the newly-created zip archive. The
/// second call to UpdateFile updates the content for that file in the zip
/// archive.
///
///
/// using (ZipFile zip1 = new ZipFile())
/// {
/// // UpdateFile might more accurately be called "AddOrUpdateFile"
/// zip1.UpdateFile("MyDocuments\\Readme.txt");
/// zip1.UpdateFile("CustomerList.csv");
/// zip1.Comment = "This zip archive has been created.";
/// zip1.Save("Content.zip");
/// }
///
/// using (ZipFile zip2 = ZipFile.Read("Content.zip"))
/// {
/// zip2.UpdateFile("Updates\\Readme.txt");
/// zip2.Comment = "This zip archive has been updated: The Readme.txt file has been changed.";
/// zip2.Save();
/// }
///
///
///
/// Using zip1 As New ZipFile
/// ' UpdateFile might more accurately be called "AddOrUpdateFile"
/// zip1.UpdateFile("MyDocuments\Readme.txt")
/// zip1.UpdateFile("CustomerList.csv")
/// zip1.Comment = "This zip archive has been created."
/// zip1.Save("Content.zip")
/// End Using
///
/// Using zip2 As ZipFile = ZipFile.Read("Content.zip")
/// zip2.UpdateFile("Updates\Readme.txt")
/// zip2.Comment = "This zip archive has been updated: The Readme.txt file has been changed."
/// zip2.Save
/// End Using
///
///
///
///
///
///
///
///
/// The name of the file to add or update. It should refer to a file in the
/// filesystem. The name of the file may be a relative path or a
/// fully-qualified path.
///
///
///
/// The ZipEntry corresponding to the File that was added or updated.
///
public ZipEntry UpdateFile(string fileName)
{
return UpdateFile(fileName, null);
}
///
/// Adds or Updates a File in a Zip file archive.
///
///
///
///
/// This method adds a file to a zip archive, or, if the file already exists
/// in the zip archive, this method Updates the content of that given filename
/// in the zip archive.
///
///
///
/// This version of the method allows the caller to explicitly specify the
/// directory path to be used in the archive. The entry to be added or
/// updated is found by using the specified directory path, combined with the
/// basename of the specified filename.
///
///
///
/// Upon success, there is no way for the application to learn if the file was
/// added versus updated.
///
///
///
/// For ZipFile properties including , , , , ,
/// , and , their
/// respective values at the time of this call will be applied to the
/// ZipEntry added.
///
///
///
///
///
///
///
///
/// The name of the file to add or update. It should refer to a file in the
/// filesystem. The name of the file may be a relative path or a
/// fully-qualified path.
///
///
///
/// Specifies a directory path to use to override any path in the
/// fileName. This path may, or may not, correspond to a real
/// directory in the current filesystem. If the files within the zip are
/// later extracted, this is the path used for the extracted file. Passing
/// null (Nothing in VB) will use the path on the
/// fileName, if any. Passing the empty string ("") will insert the
/// item at the root path within the archive.
///
///
///
/// The ZipEntry corresponding to the File that was added or updated.
///
public ZipEntry UpdateFile(string fileName, String directoryPathInArchive)
{
// ideally this would all be transactional!
var key = ZipEntry.NameInArchive(fileName, directoryPathInArchive);
if (this[key] != null)
this.RemoveEntry(key);
return this.AddFile(fileName, directoryPathInArchive);
}
///
/// Add or update a directory in a zip archive.
///
///
///
/// If the specified directory does not exist in the archive, then this method
/// is equivalent to calling AddDirectory(). If the specified
/// directory already exists in the archive, then this method updates any
/// existing entries, and adds any new entries. Any entries that are in the
/// zip archive but not in the specified directory, are left alone. In other
/// words, the contents of the zip file will be a union of the previous
/// contents and the new files.
///
///
///
///
///
///
///
/// The path to the directory to be added to the zip archive, or updated in
/// the zip archive.
///
///
///
/// The ZipEntry corresponding to the Directory that was added or updated.
///
public ZipEntry UpdateDirectory(string directoryName)
{
return UpdateDirectory(directoryName, null);
}
///
/// Add or update a directory in the zip archive at the specified root
/// directory in the archive.
///
///
///
/// If the specified directory does not exist in the archive, then this method
/// is equivalent to calling AddDirectory(). If the specified
/// directory already exists in the archive, then this method updates any
/// existing entries, and adds any new entries. Any entries that are in the
/// zip archive but not in the specified directory, are left alone. In other
/// words, the contents of the zip file will be a union of the previous
/// contents and the new files.
///
///
///
///
///
///
///
/// The path to the directory to be added to the zip archive, or updated
/// in the zip archive.
///
///
///
/// Specifies a directory path to use to override any path in the
/// directoryName. This path may, or may not, correspond to a real
/// directory in the current filesystem. If the files within the zip are
/// later extracted, this is the path used for the extracted file. Passing
/// null (Nothing in VB) will use the path on the
/// directoryName, if any. Passing the empty string ("") will insert
/// the item at the root path within the archive.
///
///
///
/// The ZipEntry corresponding to the Directory that was added or updated.
///
public ZipEntry UpdateDirectory(string directoryName, String directoryPathInArchive)
{
return this.AddOrUpdateDirectoryImpl(directoryName, directoryPathInArchive, AddOrUpdateAction.AddOrUpdate);
}
///
/// Add or update a file or directory in the zip archive.
///
///
///
///
/// This is useful when the application is not sure or does not care if the
/// item to be added is a file or directory, and does not know or does not
/// care if the item already exists in the ZipFile. Calling this method
/// is equivalent to calling RemoveEntry() if an entry by the same name
/// already exists, followed calling by AddItem().
///
///
///
/// For ZipFile properties including , , , , ,
/// , and , their
/// respective values at the time of this call will be applied to the
/// ZipEntry added.
///
///
///
///
///
///
///
///
/// the path to the file or directory to be added or updated.
///
public void UpdateItem(string itemName)
{
UpdateItem(itemName, null);
}
///
/// Add or update a file or directory.
///
///
///
///
/// This method is useful when the application is not sure or does not care if
/// the item to be added is a file or directory, and does not know or does not
/// care if the item already exists in the ZipFile. Calling this method
/// is equivalent to calling RemoveEntry(), if an entry by that name
/// exists, and then calling AddItem().
///
///
///
/// This version of the method allows the caller to explicitly specify the
/// directory path to be used for the item being added to the archive. The
/// entry or entries that are added or updated will use the specified
/// DirectoryPathInArchive. Extracting the entry from the archive will
/// result in a file stored in that directory path.
///
///
///
/// For ZipFile properties including , , , , ,
/// , and , their
/// respective values at the time of this call will be applied to the
/// ZipEntry added.
///
///
///
///
///
///
///
///
/// The path for the File or Directory to be added or updated.
///
///
/// Specifies a directory path to use to override any path in the
/// itemName. This path may, or may not, correspond to a real
/// directory in the current filesystem. If the files within the zip are
/// later extracted, this is the path used for the extracted file. Passing
/// null (Nothing in VB) will use the path on the
/// itemName, if any. Passing the empty string ("") will insert the
/// item at the root path within the archive.
///
public void UpdateItem(string itemName, string directoryPathInArchive)
{
if (File.Exists(itemName))
UpdateFile(itemName, directoryPathInArchive);
else if (Directory.Exists(itemName))
UpdateDirectory(itemName, directoryPathInArchive);
else
throw new FileNotFoundException(String.Format("That file or directory ({0}) does not exist!", itemName));
}
///
/// Adds a named entry into the zip archive, taking content for the entry
/// from a string.
///
///
///
/// Calling this method creates an entry using the given fileName and
/// directory path within the archive. There is no need for a file by the
/// given name to exist in the filesystem; the name is used within the zip
/// archive only. The content for the entry is encoded using the default text
/// encoding for the machine, or on Silverlight, using UTF-8.
///
///
///
/// The content of the file, should it be extracted from the zip.
///
///
///
/// The name, including any path, to use for the entry within the archive.
///
///
/// The ZipEntry added.
///
///
///
/// This example shows how to add an entry to the zipfile, using a string as
/// content for that entry.
///
///
/// string Content = "This string will be the content of the Readme.txt file in the zip archive.";
/// using (ZipFile zip1 = new ZipFile())
/// {
/// zip1.AddFile("MyDocuments\\Resume.doc", "files");
/// zip1.AddEntry("Readme.txt", Content);
/// zip1.Comment = "This zip file was created at " + System.DateTime.Now.ToString("G");
/// zip1.Save("Content.zip");
/// }
///
///
///
/// Public Sub Run()
/// Dim Content As String = "This string will be the content of the Readme.txt file in the zip archive."
/// Using zip1 As ZipFile = New ZipFile
/// zip1.AddEntry("Readme.txt", Content)
/// zip1.AddFile("MyDocuments\Resume.doc", "files")
/// zip1.Comment = ("This zip file was created at " & DateTime.Now.ToString("G"))
/// zip1.Save("Content.zip")
/// End Using
/// End Sub
///
///
public ZipEntry AddEntry(string entryName, string content)
{
#if SILVERLIGHT
return AddEntry(entryName, content, System.Text.Encoding.UTF8);
#else
return AddEntry(entryName, content, System.Text.Encoding.Default);
#endif
}
///
/// Adds a named entry into the zip archive, taking content for the entry
/// from a string, and using the specified text encoding.
///
///
///
///
///
/// Calling this method creates an entry using the given fileName and
/// directory path within the archive. There is no need for a file by the
/// given name to exist in the filesystem; the name is used within the zip
/// archive only.
///
///
///
/// The content for the entry, a string value, is encoded using the given
/// text encoding. A BOM (byte-order-mark) is emitted into the file, if the
/// Encoding parameter is set for that.
///
///
///
/// Most Encoding classes support a constructor that accepts a boolean,
/// indicating whether to emit a BOM or not. For example see .
///
///
///
///
///
/// The name, including any path, to use within the archive for the entry.
///
///
///
/// The content of the file, should it be extracted from the zip.
///
///
///
/// The text encoding to use when encoding the string. Be aware: This is
/// distinct from the text encoding used to encode the fileName, as specified
/// in .
///
///
/// The ZipEntry added.
///
public ZipEntry AddEntry(string entryName, string content, System.Text.Encoding encoding)
{
// cannot employ a using clause here. We need the stream to
// persist after exit from this method.
var ms = new MemoryStream();
// cannot use a using clause here; StreamWriter takes
// ownership of the stream and Disposes it before we are ready.
var sw = new StreamWriter(ms, encoding);
sw.Write(content);
sw.Flush();
// reset to allow reading later
ms.Seek(0, SeekOrigin.Begin);
return AddEntry(entryName, ms);
// must not dispose the MemoryStream - it will be used later.
}
///
/// Create an entry in the ZipFile using the given Stream
/// as input. The entry will have the given filename.
///
///
///
///
///
/// The application should provide an open, readable stream; in this case it
/// will be read during the call to or one of
/// its overloads.
///
///
///
/// The passed stream will be read from its current position. If
/// necessary, callers should set the position in the stream before
/// calling AddEntry(). This might be appropriate when using this method
/// with a MemoryStream, for example.
///
///
///
/// In cases where a large number of streams will be added to the
/// ZipFile, the application may wish to avoid maintaining all of the
/// streams open simultaneously. To handle this situation, the application
/// should use the
/// overload.
///
///
///
/// For ZipFile properties including , , , , ,
/// , and , their
/// respective values at the time of this call will be applied to the
/// ZipEntry added.
///
///
///
///
///
///
/// This example adds a single entry to a ZipFile via a Stream.
///
///
///
/// String zipToCreate = "Content.zip";
/// String fileNameInArchive = "Content-From-Stream.bin";
/// using (System.IO.Stream streamToRead = MyStreamOpener())
/// {
/// using (ZipFile zip = new ZipFile())
/// {
/// ZipEntry entry= zip.AddEntry(fileNameInArchive, streamToRead);
/// zip.AddFile("Readme.txt");
/// zip.Save(zipToCreate); // the stream is read implicitly here
/// }
/// }
///
///
///
/// Dim zipToCreate As String = "Content.zip"
/// Dim fileNameInArchive As String = "Content-From-Stream.bin"
/// Using streamToRead as System.IO.Stream = MyStreamOpener()
/// Using zip As ZipFile = New ZipFile()
/// Dim entry as ZipEntry = zip.AddEntry(fileNameInArchive, streamToRead)
/// zip.AddFile("Readme.txt")
/// zip.Save(zipToCreate) '' the stream is read implicitly, here
/// End Using
/// End Using
///
///
///
///
///
///
/// The name, including any path, which is shown in the zip file for the added
/// entry.
///
///
/// The input stream from which to grab content for the file
///
/// The ZipEntry added.
public ZipEntry AddEntry(string entryName, Stream stream)
{
ZipEntry ze = ZipEntry.CreateForStream(entryName, stream);
ze.SetEntryTimes(DateTime.Now,DateTime.Now,DateTime.Now);
if (Verbose) StatusMessageTextWriter.WriteLine("adding {0}...", entryName);
return _InternalAddEntry(ze);
}
///
/// Add a ZipEntry for which content is written directly by the application.
///
///
///
///
/// When the application needs to write the zip entry data, use this
/// method to add the ZipEntry. For example, in the case that the
/// application wishes to write the XML representation of a DataSet into
/// a ZipEntry, the application can use this method to do so.
///
///
///
/// For ZipFile properties including , , , , ,
/// , and , their
/// respective values at the time of this call will be applied to the
/// ZipEntry added.
///
///
///
/// About progress events: When using the WriteDelegate, DotNetZip does
/// not issue any SaveProgress events with EventType =
/// Saving_EntryBytesRead. (This is because it is the
/// application's code that runs in WriteDelegate - there's no way for
/// DotNetZip to know when to issue a EntryBytesRead event.)
/// Applications that want to update a progress bar or similar status
/// indicator should do so from within the WriteDelegate
/// itself. DotNetZip will issue the other SaveProgress events,
/// including
/// Saving_Started,
///
/// Saving_BeforeWriteEntry, and
/// Saving_AfterWriteEntry.
///
///
///
/// Note: When you use PKZip encryption, it's normally necessary to
/// compute the CRC of the content to be encrypted, before compressing or
/// encrypting it. Therefore, when using PKZip encryption with a
/// WriteDelegate, the WriteDelegate CAN BE called twice: once to compute
/// the CRC, and the second time to potentially compress and
/// encrypt. Surprising, but true. This is because PKWARE specified that
/// the encryption initialization data depends on the CRC.
/// If this happens, for each call of the delegate, your
/// application must stream the same entry data in its entirety. If your
/// application writes different data during the second call, it will
/// result in a corrupt zip file.
///
///
///
/// The double-read behavior happens with all types of entries, not only
/// those that use WriteDelegate. It happens if you add an entry from a
/// filesystem file, or using a string, or a stream, or an opener/closer
/// pair. But in those cases, DotNetZip takes care of reading twice; in
/// the case of the WriteDelegate, the application code gets invoked
/// twice. Be aware.
///
///
///
/// As you can imagine, this can cause performance problems for large
/// streams, and it can lead to correctness problems when you use a
/// WriteDelegate. This is a pretty big pitfall. There are two
/// ways to avoid it. First, and most preferred: don't use PKZIP
/// encryption. If you use the WinZip AES encryption, this problem
/// doesn't occur, because the encryption protocol doesn't require the CRC
/// up front. Second: if you do choose to use PKZIP encryption, write out
/// to a non-seekable stream (like standard output, or the
/// Response.OutputStream in an ASP.NET application). In this case,
/// DotNetZip will use an alternative encryption protocol that does not
/// rely on the CRC of the content. This also implies setting bit 3 in
/// the zip entry, which still presents problems for some zip tools.
///
///
///
/// In the future I may modify DotNetZip to *always* use bit 3 when PKZIP
/// encryption is in use. This seems like a win overall, but there will
/// be some work involved. If you feel strongly about it, visit the
/// DotNetZip forums and vote up the Workitem
/// tracking this issue.
///
///
///
///
/// the name of the entry to add
/// the delegate which will write the entry content
/// the ZipEntry added
///
///
///
/// This example shows an application filling a DataSet, then saving the
/// contents of that DataSet as XML, into a ZipEntry in a ZipFile, using an
/// anonymous delegate in C#. The DataSet XML is never saved to a disk file.
///
///
/// var c1= new System.Data.SqlClient.SqlConnection(connstring1);
/// var da = new System.Data.SqlClient.SqlDataAdapter()
/// {
/// SelectCommand= new System.Data.SqlClient.SqlCommand(strSelect, c1)
/// };
///
/// DataSet ds1 = new DataSet();
/// da.Fill(ds1, "Invoices");
///
/// using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile())
/// {
/// zip.AddEntry(zipEntryName, (name,stream) => ds1.WriteXml(stream) );
/// zip.Save(zipFileName);
/// }
///
///
///
///
///
/// This example uses an anonymous method in C# as the WriteDelegate to provide
/// the data for the ZipEntry. The example is a bit contrived - the
/// AddFile() method is a simpler way to insert the contents of a file
/// into an entry in a zip file. On the other hand, if there is some sort of
/// processing or transformation of the file contents required before writing,
/// the application could use the WriteDelegate to do it, in this way.
///
///
/// using (var input = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite ))
/// {
/// using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile())
/// {
/// zip.AddEntry(zipEntryName, (name,output) =>
/// {
/// byte[] buffer = new byte[BufferSize];
/// int n;
/// while ((n = input.Read(buffer, 0, buffer.Length)) != 0)
/// {
/// // could transform the data here...
/// output.Write(buffer, 0, n);
/// // could update a progress bar here
/// }
/// });
///
/// zip.Save(zipFileName);
/// }
/// }
///
///
///
///
///
/// This example uses a named delegate in VB to write data for the given
/// ZipEntry (VB9 does not have anonymous delegates). The example here is a bit
/// contrived - a simpler way to add the contents of a file to a ZipEntry is to
/// simply use the appropriate AddFile() method. The key scenario for
/// which the WriteDelegate makes sense is saving a DataSet, in XML
/// format, to the zip file. The DataSet can write XML to a stream, and the
/// WriteDelegate is the perfect place to write into the zip file. There may be
/// other data structures that can write to a stream, but cannot be read as a
/// stream. The WriteDelegate would be appropriate for those cases as
/// well.
///
///
/// Private Sub WriteEntry (ByVal name As String, ByVal output As Stream)
/// Using input As FileStream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
/// Dim n As Integer = -1
/// Dim buffer As Byte() = New Byte(BufferSize){}
/// Do While n <> 0
/// n = input.Read(buffer, 0, buffer.Length)
/// output.Write(buffer, 0, n)
/// Loop
/// End Using
/// End Sub
///
/// Public Sub Run()
/// Using zip = New ZipFile
/// zip.AddEntry(zipEntryName, New WriteDelegate(AddressOf WriteEntry))
/// zip.Save(zipFileName)
/// End Using
/// End Sub
///
///
public ZipEntry AddEntry(string entryName, WriteDelegate writer)
{
ZipEntry ze = ZipEntry.CreateForWriter(entryName, writer);
if (Verbose) StatusMessageTextWriter.WriteLine("adding {0}...", entryName);
return _InternalAddEntry(ze);
}
///
/// Add an entry, for which the application will provide a stream
/// containing the entry data, on a just-in-time basis.
///
///
///
///
/// In cases where the application wishes to open the stream that
/// holds the content for the ZipEntry, on a just-in-time basis, the
/// application can use this method. The application provides an
/// opener delegate that will be called by the DotNetZip library to
/// obtain a readable stream that can be read to get the bytes for
/// the given entry. Typically, this delegate opens a stream.
/// Optionally, the application can provide a closer delegate as
/// well, which will be called by DotNetZip when all bytes have been
/// read from the entry.
///
///
///
/// These delegates are called from within the scope of the call to
/// ZipFile.Save().
///
///
///
/// For ZipFile properties including , , , , ,
/// , and , their
/// respective values at the time of this call will be applied to the
/// ZipEntry added.
///
///
///
///
///
///
/// This example uses anonymous methods in C# to open and close the
/// source stream for the content for a zip entry.
///
///
/// using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile())
/// {
/// zip.AddEntry(zipEntryName,
/// (name) => File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite ),
/// (name, stream) => stream.Close()
/// );
///
/// zip.Save(zipFileName);
/// }
///
///
///
///
///
///
/// This example uses delegates in VB.NET to open and close the
/// the source stream for the content for a zip entry. VB 9.0 lacks
/// support for "Sub" lambda expressions, and so the CloseDelegate must
/// be an actual, named Sub.
///
///
///
/// Function MyStreamOpener(ByVal entryName As String) As Stream
/// '' This simply opens a file. You probably want to do somethinig
/// '' more involved here: open a stream to read from a database,
/// '' open a stream on an HTTP connection, and so on.
/// Return File.OpenRead(entryName)
/// End Function
///
/// Sub MyStreamCloser(entryName As String, stream As Stream)
/// stream.Close()
/// End Sub
///
/// Public Sub Run()
/// Dim dirToZip As String = "fodder"
/// Dim zipFileToCreate As String = "Archive.zip"
/// Dim opener As OpenDelegate = AddressOf MyStreamOpener
/// Dim closer As CloseDelegate = AddressOf MyStreamCloser
/// Dim numFilestoAdd As Int32 = 4
/// Using zip As ZipFile = New ZipFile
/// Dim i As Integer
/// For i = 0 To numFilesToAdd - 1
/// zip.AddEntry(String.Format("content-{0:000}.txt"), opener, closer)
/// Next i
/// zip.Save(zipFileToCreate)
/// End Using
/// End Sub
///
///
///
///
/// the name of the entry to add
///
/// the delegate that will be invoked by ZipFile.Save() to get the
/// readable stream for the given entry. ZipFile.Save() will call
/// read on this stream to obtain the data for the entry. This data
/// will then be compressed and written to the newly created zip
/// file.
///
///
/// the delegate that will be invoked to close the stream. This may
/// be null (Nothing in VB), in which case no call is makde to close
/// the stream.
///
/// the ZipEntry added
///
public ZipEntry AddEntry(string entryName, OpenDelegate opener, CloseDelegate closer)
{
ZipEntry ze = ZipEntry.CreateForJitStreamProvider(entryName, opener, closer);
ze.SetEntryTimes(DateTime.Now,DateTime.Now,DateTime.Now);
if (Verbose) StatusMessageTextWriter.WriteLine("adding {0}...", entryName);
return _InternalAddEntry(ze);
}
private ZipEntry _InternalAddEntry(ZipEntry ze)
{
// stamp all the props onto the entry
ze._container = new ZipContainer(this);
ze.CompressionMethod = this.CompressionMethod;
ze.CompressionLevel = this.CompressionLevel;
ze.ExtractExistingFile = this.ExtractExistingFile;
ze.ZipErrorAction = this.ZipErrorAction;
ze.SetCompression = this.SetCompression;
ze.AlternateEncoding = this.AlternateEncoding;
ze.AlternateEncodingUsage = this.AlternateEncodingUsage;
ze.Password = this._Password;
ze.Encryption = this.Encryption;
ze.EmitTimesInWindowsFormatWhenSaving = this._emitNtfsTimes;
ze.EmitTimesInUnixFormatWhenSaving = this._emitUnixTimes;
//string key = DictionaryKeyForEntry(ze);
InternalAddEntry(ze.FileName,ze);
AfterAddEntry(ze);
return ze;
}
///
/// Updates the given entry in the ZipFile, using the given
/// string as content for the ZipEntry.
///
///
///
///
///
/// Calling this method is equivalent to removing the ZipEntry for
/// the given file name and directory path, if it exists, and then calling
/// . See the documentation for
/// that method for further explanation. The string content is encoded
/// using the default encoding for the machine, or on Silverlight, using
/// UTF-8. This encoding is distinct from the encoding used for the
/// filename itself. See .
///
///
///
///
///
/// The name, including any path, to use within the archive for the entry.
///
///
///
/// The content of the file, should it be extracted from the zip.
///
///
/// The ZipEntry added.
///
public ZipEntry UpdateEntry(string entryName, string content)
{
#if SILVERLIGHT
return UpdateEntry(entryName, content, System.Text.Encoding.UTF8);
#else
return UpdateEntry(entryName, content, System.Text.Encoding.Default);
#endif
}
///
/// Updates the given entry in the ZipFile, using the given string as
/// content for the ZipEntry.
///
///
///
/// Calling this method is equivalent to removing the ZipEntry for the
/// given file name and directory path, if it exists, and then calling . See the
/// documentation for that method for further explanation.
///
///
///
/// The name, including any path, to use within the archive for the entry.
///
///
///
/// The content of the file, should it be extracted from the zip.
///
///
///
/// The text encoding to use when encoding the string. Be aware: This is
/// distinct from the text encoding used to encode the filename. See .
///
///
/// The ZipEntry added.
///
public ZipEntry UpdateEntry(string entryName, string content, System.Text.Encoding encoding)
{
RemoveEntryForUpdate(entryName);
return AddEntry(entryName, content, encoding);
}
///
/// Updates the given entry in the ZipFile, using the given delegate
/// as the source for content for the ZipEntry.
///
///
///
/// Calling this method is equivalent to removing the ZipEntry for the
/// given file name and directory path, if it exists, and then calling . See the
/// documentation for that method for further explanation.
///
///
///
/// The name, including any path, to use within the archive for the entry.
///
///
/// the delegate which will write the entry content.
///
/// The ZipEntry added.
///
public ZipEntry UpdateEntry(string entryName, WriteDelegate writer)
{
RemoveEntryForUpdate(entryName);
return AddEntry(entryName, writer);
}
///
/// Updates the given entry in the ZipFile, using the given delegates
/// to open and close the stream that provides the content for the ZipEntry.
///
///
///
/// Calling this method is equivalent to removing the ZipEntry for the
/// given file name and directory path, if it exists, and then calling . See the
/// documentation for that method for further explanation.
///
///
///
/// The name, including any path, to use within the archive for the entry.
///
///
///
/// the delegate that will be invoked to open the stream
///
///
/// the delegate that will be invoked to close the stream
///
///
/// The ZipEntry added or updated.
///
public ZipEntry UpdateEntry(string entryName, OpenDelegate opener, CloseDelegate closer)
{
RemoveEntryForUpdate(entryName);
return AddEntry(entryName, opener, closer);
}
///
/// Updates the given entry in the ZipFile, using the given stream as
/// input, and the given filename and given directory Path.
///
///
///
///
/// Calling the method is equivalent to calling RemoveEntry() if an
/// entry by the same name already exists, and then calling AddEntry()
/// with the given fileName and stream.
///
///
///
/// The stream must be open and readable during the call to
/// ZipFile.Save. You can dispense the stream on a just-in-time basis
/// using the property. Check the
/// documentation of that property for more information.
///
///
///
/// For ZipFile properties including , , , , ,
/// , and , their
/// respective values at the time of this call will be applied to the
/// ZipEntry added.
///
///
///
///
///
///
///
///
/// The name, including any path, to use within the archive for the entry.
///
///
/// The input stream from which to read file data.
/// The ZipEntry added.
public ZipEntry UpdateEntry(string entryName, Stream stream)
{
RemoveEntryForUpdate(entryName);
return AddEntry(entryName, stream);
}
private void RemoveEntryForUpdate(string entryName)
{
if (String.IsNullOrEmpty(entryName))
throw new ArgumentNullException("entryName");
string directoryPathInArchive = null;
if (entryName.IndexOf('\\') != -1)
{
directoryPathInArchive = Path.GetDirectoryName(entryName);
entryName = Path.GetFileName(entryName);
}
var key = ZipEntry.NameInArchive(entryName, directoryPathInArchive);
if (this[key] != null)
this.RemoveEntry(key);
}
///
/// Add an entry into the zip archive using the given filename and
/// directory path within the archive, and the given content for the
/// file. No file is created in the filesystem.
///
///
/// The data to use for the entry.
///
///
/// The name, including any path, to use within the archive for the entry.
///
///
/// The ZipEntry added.
public ZipEntry AddEntry(string entryName, byte[] byteContent)
{
if (byteContent == null) throw new ArgumentException("bad argument", "byteContent");
var ms = new MemoryStream(byteContent);
return AddEntry(entryName, ms);
}
///
/// Updates the given entry in the ZipFile, using the given byte
/// array as content for the entry.
///
///
///
/// Calling this method is equivalent to removing the ZipEntry
/// for the given filename and directory path, if it exists, and then
/// calling . See the
/// documentation for that method for further explanation.
///
///
///
/// The name, including any path, to use within the archive for the entry.
///
///
/// The content to use for the ZipEntry.
///
/// The ZipEntry added.
///
public ZipEntry UpdateEntry(string entryName, byte[] byteContent)
{
RemoveEntryForUpdate(entryName);
return AddEntry(entryName, byteContent);
}
// private string DictionaryKeyForEntry(ZipEntry ze1)
// {
// var filename = SharedUtilities.NormalizePathForUseInZipFile(ze1.FileName);
// return filename;
// }
///
/// Adds the contents of a filesystem directory to a Zip file archive.
///
///
///
///
///
/// The name of the directory may be a relative path or a fully-qualified
/// path. Any files within the named directory are added to the archive. Any
/// subdirectories within the named directory are also added to the archive,
/// recursively.
///
///
///
/// Top-level entries in the named directory will appear as top-level entries
/// in the zip archive. Entries in subdirectories in the named directory will
/// result in entries in subdirectories in the zip archive.
///
///
///
/// If you want the entries to appear in a containing directory in the zip
/// archive itself, then you should call the AddDirectory() overload that
/// allows you to explicitly specify a directory path for use in the archive.
///
///
///
/// For ZipFile properties including , , , , ,
/// , and , their
/// respective values at the time of this call will be applied to each
/// ZipEntry added.
///
///
///
///
///
///
///
///
///
/// This method has 2 overloads.
///
/// The name of the directory to add.
/// The ZipEntry added.
public ZipEntry AddDirectory(string directoryName)
{
return AddDirectory(directoryName, null);
}
///
/// Adds the contents of a filesystem directory to a Zip file archive,
/// overriding the path to be used for entries in the archive.
///
///
///
///
/// The name of the directory may be a relative path or a fully-qualified
/// path. The add operation is recursive, so that any files or subdirectories
/// within the name directory are also added to the archive.
///
///
///
/// Top-level entries in the named directory will appear as top-level entries
/// in the zip archive. Entries in subdirectories in the named directory will
/// result in entries in subdirectories in the zip archive.
///
///
///
/// For ZipFile properties including , , , , ,
/// , and , their
/// respective values at the time of this call will be applied to each
/// ZipEntry added.
///
///
///
///
///
///
/// In this code, calling the ZipUp() method with a value of "c:\reports" for
/// the directory parameter will result in a zip file structure in which all
/// entries are contained in a toplevel "reports" directory.
///
///
///
/// public void ZipUp(string targetZip, string directory)
/// {
/// using (var zip = new ZipFile())
/// {
/// zip.AddDirectory(directory, System.IO.Path.GetFileName(directory));
/// zip.Save(targetZip);
/// }
/// }
///
///
///
///
///
///
///
/// The name of the directory to add.
///
///
/// Specifies a directory path to use to override any path in the
/// DirectoryName. This path may, or may not, correspond to a real directory
/// in the current filesystem. If the zip is later extracted, this is the
/// path used for the extracted file or directory. Passing null
/// (Nothing in VB) or the empty string ("") will insert the items at
/// the root path within the archive.
///
///
/// The ZipEntry added.
public ZipEntry AddDirectory(string directoryName, string directoryPathInArchive)
{
return AddOrUpdateDirectoryImpl(directoryName, directoryPathInArchive, AddOrUpdateAction.AddOnly);
}
///
/// Creates a directory in the zip archive.
///
///
///
///
///
/// Use this when you want to create a directory in the archive but there is
/// no corresponding filesystem representation for that directory.
///
///
///
/// You will probably not need to do this in your code. One of the only times
/// you will want to do this is if you want an empty directory in the zip
/// archive. The reason: if you add a file to a zip archive that is stored
/// within a multi-level directory, all of the directory tree is implicitly
/// created in the zip archive.
///
///
///
///
///
/// The name of the directory to create in the archive.
///
/// The ZipEntry added.
public ZipEntry AddDirectoryByName(string directoryNameInArchive)
{
// workitem 9073
ZipEntry dir = ZipEntry.CreateFromNothing(directoryNameInArchive);
dir._container = new ZipContainer(this);
dir.MarkAsDirectory();
dir.AlternateEncoding = this.AlternateEncoding; // workitem 8984
dir.AlternateEncodingUsage = this.AlternateEncodingUsage;
dir.SetEntryTimes(DateTime.Now,DateTime.Now,DateTime.Now);
dir.EmitTimesInWindowsFormatWhenSaving = _emitNtfsTimes;
dir.EmitTimesInUnixFormatWhenSaving = _emitUnixTimes;
dir._Source = ZipEntrySource.Stream;
//string key = DictionaryKeyForEntry(dir);
InternalAddEntry(dir.FileName,dir);
AfterAddEntry(dir);
return dir;
}
private ZipEntry AddOrUpdateDirectoryImpl(string directoryName,
string rootDirectoryPathInArchive,
AddOrUpdateAction action)
{
if (rootDirectoryPathInArchive == null)
{
rootDirectoryPathInArchive = "";
}
return AddOrUpdateDirectoryImpl(directoryName, rootDirectoryPathInArchive, action, true, 0);
}
internal void InternalAddEntry(String name, ZipEntry entry)
{
_entries.Add(name, entry);
_zipEntriesAsList = null;
_contentsChanged = true;
}
private ZipEntry AddOrUpdateDirectoryImpl(string directoryName,
string rootDirectoryPathInArchive,
AddOrUpdateAction action,
bool recurse,
int level)
{
if (Verbose)
StatusMessageTextWriter.WriteLine("{0} {1}...",
(action == AddOrUpdateAction.AddOnly) ? "adding" : "Adding or updating",
directoryName);
if (level == 0)
{
_addOperationCanceled = false;
OnAddStarted();
}
// workitem 13371
if (_addOperationCanceled)
return null;
string dirForEntries = rootDirectoryPathInArchive;
ZipEntry baseDir = null;
if (level > 0)
{
int f = directoryName.Length;
for (int i = level; i > 0; i--)
f = directoryName.LastIndexOfAny("/\\".ToCharArray(), f - 1, f - 1);
dirForEntries = directoryName.Substring(f + 1);
dirForEntries = Path.Combine(rootDirectoryPathInArchive, dirForEntries);
}
// if not top level, or if the root is non-empty, then explicitly add the directory
if (level > 0 || rootDirectoryPathInArchive != "")
{
baseDir = ZipEntry.CreateFromFile(directoryName, dirForEntries);
baseDir._container = new ZipContainer(this);
baseDir.AlternateEncoding = this.AlternateEncoding; // workitem 6410
baseDir.AlternateEncodingUsage = this.AlternateEncodingUsage;
baseDir.MarkAsDirectory();
baseDir.EmitTimesInWindowsFormatWhenSaving = _emitNtfsTimes;
baseDir.EmitTimesInUnixFormatWhenSaving = _emitUnixTimes;
// add the directory only if it does not exist.
// It's not an error if it already exists.
if (!_entries.ContainsKey(baseDir.FileName))
{
InternalAddEntry(baseDir.FileName,baseDir);
AfterAddEntry(baseDir);
}
dirForEntries = baseDir.FileName;
}
if (!_addOperationCanceled)
{
String[] filenames = Directory.GetFiles(directoryName);
if (recurse)
{
// add the files:
foreach (String filename in filenames)
{
if (_addOperationCanceled) break;
if (action == AddOrUpdateAction.AddOnly)
AddFile(filename, dirForEntries);
else
UpdateFile(filename, dirForEntries);
}
if (!_addOperationCanceled)
{
// add the subdirectories:
String[] dirnames = Directory.GetDirectories(directoryName);
foreach (String dir in dirnames)
{
// workitem 8617: Optionally traverse reparse points
#if SILVERLIGHT
#elif NETCF
FileAttributes fileAttrs = (FileAttributes) NetCfFile.GetAttributes(dir);
#else
FileAttributes fileAttrs = System.IO.File.GetAttributes(dir);
#endif
if (this.AddDirectoryWillTraverseReparsePoints
#if !SILVERLIGHT
|| ((fileAttrs & FileAttributes.ReparsePoint) == 0)
#endif
)
AddOrUpdateDirectoryImpl(dir, rootDirectoryPathInArchive, action, recurse, level + 1);
}
}
}
}
if (level == 0)
OnAddCompleted();
return baseDir;
}
}
}