使用 Packaging 命名空间的 .NET Framework Zip / UnZip 工具






3.14/5 (12投票s)
一个可以用来压缩和解压缩文件的 UI 工具。
引言
此工具可用于创建 Zip 文件、查看 Zip 文件以及将选定的 Zip 文件解压缩到用户指定的位置。创建 Zip 文件支持添加文件、在 Zip 中创建文件夹以及删除现有文件和文件夹。
背景
对于此工具,我使用了 .NET Framework 3.5 的 System.IO.Packaging.Package
命名空间。 此外,我使用了扩展方法来扩展 NodesCollection
类的功能。如果您不了解这一点,请参考 MSDN。
使用代码
要使用此工具,您需要在您的机器上安装 .NET Framework 3.5。如果您计划查看代码,则需要安装 Visual Studio 2008。 此工具使用非常简单。 默认情况下它有一个根节点,不能被删除。 如果用户想要创建一个 Zip 文件,第一步是清除树视图控件。 这是通过使用屏幕左侧提供的“清除”按钮完成的。 第二步是添加文件/文件夹。 此功能通过使用树视图节点的上下文菜单提供。 一旦用户准备好了虚拟 Zip 文件,请使用“Zip”按钮选择一个物理文件夹和文件来创建物理 zip 文件。 要查看 Zip 文件,用户可以单击左侧的“查看”按钮。 这将提示一个文件对话框窗口来选择 Zip 文件。 一旦用户选择了 Zip 文件,完整 Zip 文件的虚拟结构将以树形格式表示。 请注意,目前,此工具不支持修改现有的 Zip 文件。 此工具的设计确实支持集成此功能。 要解压缩 Zip 文件,请单击“解压缩”按钮。 这将允许您选择一个 Zip 文件以及文件需要解压缩到的位置。
注意:此工具可以扩展以获得更高级的功能。 但是,目前,开发此工具是为了了解用于 Microsoft Office 2007 文档创建和更新的幕后代码处理过程。
对于使用 System.IO.Packaging.Package
命名空间的此原型代码版本,每个按钮的处理都写在 UI 窗体的幕后代码中。 最好的方法是拥有一个单独的服务类来支持这些功能。
/*
UI that uses Packaging Namespace of .Net Framework 3.5 for
creation of Zip file. This tool does zipping of single and multiple files
* Developer : Mayur H Chauhan
* Location : Iselin USA
* Date : 09/02/2008
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Packaging;
namespace ZipFile
{
public partial class frmZipTool : Form
{
#region " List of member identifier"
private FolderNode root = null;
private ContextMenu _contextMenu = null;
#endregion
#region " Methods to Initialize UI"
public frmZipTool()
{
InitializeComponent();
}
private void frmZipTool_Load(object sender, EventArgs e)
{
ClearTree();
// Define context menu and set
// it to only Folder node and Root node
_contextMenu = new ContextMenu();
MenuItem addfile = new MenuItem("Add File(s)",
new EventHandler(AddFilesMenuClick));
_contextMenu.MenuItems.Add(addfile);
MenuItem createfolder = new MenuItem("Create Folder",
new EventHandler(CreateFolderMenuClick));
_contextMenu.MenuItems.Add(createfolder);
MenuItem delete = new MenuItem("Delete",
new EventHandler(DeleteMenuClick));
_contextMenu.MenuItems.Add(delete);
tvFilesAndFolders.ContextMenu = _contextMenu;
tvFilesAndFolders.SelectedNode = root;
}
#endregion
#region"Method related to context menu"
/// <summary>
/// Method to execute Add File(s) process of menu click
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void AddFilesMenuClick(object sender, EventArgs e)
{
System.Text.StringBuilder filesNotAdded =
new System.Text.StringBuilder();
//add all the files that is been selected by the user
TreeNode parentNode = ((TreeView)((System.Windows.Forms.MenuItem)
(sender)).GetContextMenu().SourceControl).SelectedNode;
// Check for the type of the node selected.
// If it is Folder Type, then allow user to add file.
// Else show message and cancel the further process.
if (parentNode.GetType() == typeof(FolderNode))
{
using (OpenFileDialog openfileDialog = new OpenFileDialog())
{
openfileDialog.Filter = "All Files|*.*";
openfileDialog.Multiselect = true;
if (openfileDialog.ShowDialog() != DialogResult.Cancel)
{
foreach (string file in openfileDialog.FileNames)
{
//Check for file with these name already exists.
//If so then we need to show some kind of message.
if (parentNode.Nodes.ContainsKey(
System.IO.Path.GetFileName(file)) == false)
{
FileNode newfile =
new FileNode(System.IO.Path.GetFileName(file));
newfile.Text = System.IO.Path.GetFileName(file);
newfile.Tag = file;
newfile.fileStorageType =
FileNode.enumFileStorageType.enmPhysicalFile;
parentNode.Nodes.Add(newfile);
parentNode.ExpandAll();
}
else
{
if (filesNotAdded.Length > 0)
{
filesNotAdded.Append("\n");
}
else
{ }
filesNotAdded.Append(System.IO.Path.GetFileName(file));
}
}
//Check for any file not added. If so,
//then we need so show message to the user
if (filesNotAdded.Length > 0)
{
System.Text.StringBuilder message =
new System.Text.StringBuilder();
message.Append("Following file(s) are not" +
" added as there already " +
"exists file with same name");
message.Append("\n\n");
message.Append(filesNotAdded.ToString());
showMessage(message.ToString(),
MessageBoxButtons.OK);
}
else
{
//do nothing
}
}
}
}
else
{
MessageBox.Show("Files can be added only to the Folder Node");
}
}
/// <summary>
/// Method to execute create Folder process of menu click
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void CreateFolderMenuClick(object sender, EventArgs e)
{
TreeNode parentNode = ((TreeView)((System.Windows.Forms.MenuItem)
(sender)).GetContextMenu().SourceControl).SelectedNode;
// Check for the type of the node selected.
// If it is Folder Type, then allow user to add file.
// Else show message and cancel the further process.
if (parentNode.GetType() == typeof(FolderNode))
{
// Here we need to create node
// of type Folder Node and give name to it
string folderName =
Microsoft.VisualBasic.Interaction.InputBox(
"Enter folder name", ".Net 3.5 Tool", string.Empty,
MousePosition.X, MousePosition.Y);
if (folderName.Equals(string.Empty) == false)
{
//Check for the folder already exists with this name.
//If so then we need to show
//message and ignore adding this folder.
if (parentNode.Nodes.ContainsKey(folderName))
{
System.Text.StringBuilder message =
new System.Text.StringBuilder();
message.Append("Folder with name ");
message.Append(folderName);
message.Append(" already exists");
showMessage(message.ToString(), MessageBoxButtons.OK);
message = null;
}
else
{
FolderNode newFolder = new FolderNode(folderName);
newFolder.Text = folderName;
parentNode.Nodes.Add(newFolder);
parentNode.ExpandAll();
}
}
}
else
{
MessageBox.Show("Folder can be created only to Folder Node");
}
}
/// <summary>
/// Method to execute Delete process of Menu click
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void DeleteMenuClick(object sender, EventArgs e)
{
//Here check for the type of the Node. If it is Root node,
//then do not allow user to delete that node
TreeNode nodeToDelete = ((TreeView)((System.Windows.Forms.MenuItem)
(sender)).GetContextMenu().SourceControl).SelectedNode;
if (nodeToDelete.Equals(root))
{
showMessage("Root Node cannot be deleted", MessageBoxButtons.OK );
}
else
{
//Check for the type of the node. If it is Folder node
//and if it has any child node then show the warning.
if (nodeToDelete.GetType() == typeof(FolderNode))
{
if (nodeToDelete.Nodes.Count > 0)
{
if (showMessage("Deleting this folder will remove all " +
"the file(s) and folder(s) under it." +
" Do you want to continue ?",
MessageBoxButtons.OKCancel) == DialogResult.OK)
{
nodeToDelete.Remove();
}
else
{
//Cancel delete process
}
}
else
{
if (showMessage("Do you want to delete selected folder ?",
MessageBoxButtons.OKCancel) == DialogResult.OK)
{
nodeToDelete.Remove();
}
else
{
//Cancel this process
}
}
}
else
{
if (showMessage("Do you want to delete selected file ?",
MessageBoxButtons.OKCancel) == DialogResult.OK)
{
nodeToDelete.Remove();
}
else
{
//Cancel this process
}
}
}
}
#endregion
#region"Method to clear Tree"
/// <summary>
/// Clear all the nodes except Root node
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnClear_Click(object sender, EventArgs e)
{
ClearTree();
}
/// <summary>
/// Method to clear Tree
/// </summary>
protected void ClearTree()
{
// By default have one Root Node
root = new FolderNode();
root.Text = "./";
root.Name = "root";
tvFilesAndFolders.Nodes.Clear();
tvFilesAndFolders.Nodes.Add(root);
}
#endregion
#region " Method to create Zip file"
private void btnZip_Click(object sender, EventArgs e)
{
string zipFilePath = string.Empty;
toolStripStatusLabel2.Text = " In Process";
using (SaveFileDialog saveFileDialog = new SaveFileDialog())
{
saveFileDialog.Filter = "Zip File| *.zip";
saveFileDialog.DefaultExt = ".zip";
saveFileDialog.OverwritePrompt = true;
if (saveFileDialog.ShowDialog() != DialogResult.Cancel)
{
zipFilePath = saveFileDialog.FileName;
}
}
//Create Zip file
if (zipFilePath != string.Empty)
{
try
{
if (System.IO.File.Exists(zipFilePath))
{
System.IO.File.Delete(zipFilePath);
}
}
catch
{ }
System.IO.Packaging.Package ZipFile =
System.IO.Packaging.ZipPackage.Open(zipFilePath,
System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite);
//Itterate through the all the sublings of the root node and
//add them within the zip file. There is possible that the child
//nodes can be an file node or it can be and Folder node.
//In case if it is folder node, then there is possiblity
//that it can have child nodes below it.
AddFilesAndFolder(root, ZipFile);
ZipFile.Close();
}
else
{
// do nothing
}
toolStripStatusLabel2.Text = " Process Completed";
}
/// <summary>
/// Method to add files and folder within the zip file
/// </summary>
/// <param name="zipFilePackage"></param>
protected void AddFilesAndFolder(TreeNode rootnode,
System.IO.Packaging.Package zipFilePackage)
{
//Check for the type of the node. In case of the Root node,
//the type would be tree node. In case of user
//defined folder node, it would be FolderNode
System.Type nodeType = rootnode.GetType();
if ((nodeType == typeof(TreeNode)) || (nodeType == typeof(FolderNode)))
{
foreach (TreeNode childNode in rootnode.Nodes)
{
if (childNode.GetType() == typeof(FileNode))
{
//Add the file within the package
AddFileToZip(((FileNode)childNode), zipFilePackage);
}
else if (childNode.GetType() == typeof(FolderNode))
{
AddFilesAndFolder(childNode, zipFilePackage);
}
}
}
}
/// <summary>
/// Method to add files and folder within the zip file package
/// </summary>
/// <param name="parentnode"></param>
/// <param name="zipFile"></param>
protected void AddFileToZip(FileNode filenode,
System.IO.Packaging.Package zipFilePackage)
{
//Here get the file node and add it in the Zip file. Make sure
//to maintain the folder structure that is defined within the tree view.
string physicalfilePath = (string)filenode.Tag;
//Check for file existing. If file does not exists,
//then add in the report to generate at the end of the process.
if (System.IO.File.Exists(physicalfilePath))
{
string treeFilePath = filenode.FullPath;
// Remove the section of the path that has "root defined"
treeFilePath = treeFilePath.Replace("./", "");
// Incase if there is space in the file name, then this won't work.
// So we need to remove space from the file name and replace it with "_"
string fileName = System.IO.Path.GetFileName(treeFilePath);
treeFilePath = treeFilePath.Replace(fileName,
fileName.Replace(" ", "_"));
//create Packagepart that will represent file that we will add.
//Define URI for this file that needs to be added within the Zip file.
//Define the added file as related to the Zip file in terms of the path.
//This part will define the location where this file needs
//to be extracted while the zip file is getting exteacted.
Uri partURI = new Uri(treeFilePath, UriKind.Relative);
string contentType = System.Net.Mime.MediaTypeNames.Application.Zip;
//Define the Content Type of the file that we will be adding.
//This depends upon the file extension
switch (System.IO.Path.GetExtension(treeFilePath).ToLower())
{
case (".xml"):
{
contentType = System.Net.Mime.MediaTypeNames.Text.Xml;
break;
}
case (".txt"):
{
contentType = System.Net.Mime.MediaTypeNames.Text.Plain;
break;
}
case (".rtf"):
{
contentType = System.Net.Mime.MediaTypeNames.Application.Rtf;
break;
}
case (".gif"):
{
contentType = System.Net.Mime.MediaTypeNames.Image.Gif;
break;
}
case (".jpeg"):
{
contentType = System.Net.Mime.MediaTypeNames.Image.Jpeg;
break;
}
case (".tiff"):
{
contentType = System.Net.Mime.MediaTypeNames.Image.Tiff;
break;
}
case (".pdf"):
{
contentType =
System.Net.Mime.MediaTypeNames.Application.Pdf;
break;
}
case (".doc"):
case (".docx"):
case (".ppt"):
case (".xls"):
{
contentType = System.Net.Mime.MediaTypeNames.Text.RichText;
break;
}
}
System.IO.Packaging.PackagePart newFilePackagePart =
zipFilePackage.CreatePart(partURI,
contentType, CompressionOption.Normal);
byte[] fileContent = System.IO.File.ReadAllBytes(physicalfilePath);
newFilePackagePart.GetStream().Write(fileContent, 0, fileContent.Length);
}
else
{
// Add within the collection and use it to generate report.
}
}
#endregion
#region " Method(s) to close the application"
private void btnClose_Click(object sender, EventArgs e)
{
this.Close();
}
#endregion
#region "Methods to view Zip file content"
/// <summary>
/// Method to view Zip file content
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnView_Click(object sender, EventArgs e)
{
//Here we can go though all the subpackage within the Zip file package
//and create its node within the Tree view. In case if it has folder,
//then we need to create folder node within the tree view and represent it
toolStripStatusLabel2.Text = "In Process";
string zipFilePath = string.Empty;
// Method to unzip file selected to the selected location
using (OpenFileDialog openFileDialog = new OpenFileDialog())
{
openFileDialog.Filter = "Zip file|*.zip";
openFileDialog.CheckFileExists = true;
openFileDialog.Multiselect = false;
openFileDialog.DefaultExt = ".zip";
if (openFileDialog.ShowDialog() != DialogResult.Cancel)
{
zipFilePath = openFileDialog.FileName;
}
}
if (zipFilePath != string.Empty)
{
System.IO.Packaging.Package zipFilePackage =
System.IO.Packaging.ZipPackage.Open(zipFilePath,
System.IO.FileMode.Open, System.IO.FileAccess.ReadWrite);
//Iterate through the all the files
//that is added within the collection and
foreach (System.IO.Packaging.ZipPackagePart
contentFile in zipFilePackage.GetParts())
{
createFileNode(contentFile);
}
zipFilePackage.Close();
tvFilesAndFolders.ExpandAll();
}
else
{
//do nothing
}
toolStripStatusLabel2.Text = " Process Completed";
}
/// <summary>
/// Method to create file at the temp folder
/// </summary>
/// <param name="rootFolder"></param>
/// <param name="contentFileURI"></param>
/// <returns></returns>
protected void createFileNode(System.IO.Packaging.ZipPackagePart contentFile)
{
// Here we need to create folder and sub folder
// for showing the provided package part within the tree.
// Initially create file under the folder specified
string contentFilePath = contentFile.Uri.OriginalString;
//Call method to create Directory within the Root directory
//and then add the file within that directory
FolderNode parentFolderNode = createDirectory(
System.IO.Path.GetDirectoryName(contentFilePath));
FileNode file =
new FileNode(System.IO.Path.GetFileName(contentFilePath));
file.fileStorageType = FileNode.enumFileStorageType.enmTextStream;
file.Text = System.IO.Path.GetFileName(contentFilePath);
file.Tag = contentFile;
parentFolderNode.Nodes.Add(file);
}
/// <summary>
/// Method to create di
/// </summary>
/// <param name="directoryPath"></param>
/// <returns></returns>
protected FolderNode createDirectory(string directoryPath)
{
//Here we need to check for the folder an the sub folder exists.
//If not then create folder. Once all the folder and sub folder
//is created, then return the immediate parent of the file that
//is defined within the directory path.
//In other words, return last sub folder.
string[] directoryList = directoryPath.Split('\\');
FolderNode currentNode = root;
foreach (string subdirectory in directoryList)
{
if (subdirectory!= string.Empty)
{
if (currentNode.Nodes.ContainsKey(subdirectory) == false)
{
FolderNode subDirectoryNode = new FolderNode(subdirectory);
subDirectoryNode.Text = subdirectory;
currentNode.Nodes.Add(subDirectoryNode);
currentNode = subDirectoryNode;
}
else
{
//do nothing as folder is already created
currentNode =
(FolderNode)currentNode.Nodes.GetNodeByKey(subdirectory);
}
}
else
{
//do nothing
}
}
return currentNode;
}
#endregion
#region" Method to Unzip file at selected location"
/// <summary>
/// Method to unzip Zip file at specified location
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnUnZip_Click(object sender, EventArgs e)
{
toolStripStatusLabel2.Text = "In Process";
string zipFilePath = string.Empty;
// Method to unzip file selected to the selected location
using (OpenFileDialog openFileDialog = new OpenFileDialog())
{
openFileDialog.Filter = "Zip file|*.zip";
openFileDialog.CheckFileExists = true;
openFileDialog.Multiselect = false;
openFileDialog.DefaultExt = ".zip";
if (openFileDialog.ShowDialog() != DialogResult.Cancel)
{
zipFilePath = openFileDialog.FileName;
}
}
if (zipFilePath != string.Empty)
{
string unZipFolderLocation = string.Empty;
using (FolderBrowserDialog unzipFolderLocation =
new FolderBrowserDialog())
{
unzipFolderLocation.RootFolder =
Environment.SpecialFolder.DesktopDirectory;
unzipFolderLocation.Description = "Select Folder to Unzip " +
System.IO.Path.GetFileName(zipFilePath) + " zip file";
if (unzipFolderLocation.ShowDialog() != DialogResult.Cancel)
{
unZipFolderLocation = unzipFolderLocation.SelectedPath;
}
else
{
//do nothing
}
}
if ((zipFilePath != string.Empty) && (unZipFolderLocation != string.Empty))
{
System.IO.Packaging.Package zipFilePackage =
System.IO.Packaging.ZipPackage.Open(zipFilePath,
System.IO.FileMode.Open, System.IO.FileAccess.ReadWrite);
//Iterate through the all the files that
//is added within the collection and
foreach (System.IO.Packaging.ZipPackagePart
contentFile in zipFilePackage.GetParts())
{
createFile(unZipFolderLocation, contentFile);
}
zipFilePackage.Close();
if (showMessage("Do you want to view selected zip file",
MessageBoxButtons.OKCancel) == DialogResult.OK)
{
// Display within the view
zipFilePackage = System.IO.Packaging.ZipPackage.Open(zipFilePath,
System.IO.FileMode.Open,
System.IO.FileAccess.ReadWrite);
//Iterate through the all the files that
//is added within the collection and
foreach (System.IO.Packaging.ZipPackagePart
contentFile in zipFilePackage.GetParts())
{
createFileNode(contentFile);
}
zipFilePackage.Close();
tvFilesAndFolders.ExpandAll();
}
else
{
//do nothing
}
}
else
{
// do nothing
}
}
else
{
//do nothing
}
toolStripStatusLabel2.Text = " Process Completed";
}
/// <summary>
/// Method to create file at the temp folder
/// </summary>
/// <param name="rootFolder"></param>
/// <param name="contentFileURI"></param>
/// <returns></returns>
protected void createFile(string rootFolder,
System.IO.Packaging.ZipPackagePart contentFile)
{
// Initially create file under the folder specified
string contentFilePath = string.Empty;
contentFilePath =contentFile.Uri.OriginalString.Replace('/',
System.IO.Path.DirectorySeparatorChar);
if (contentFilePath.StartsWith(
System.IO.Path.DirectorySeparatorChar.ToString()))
{
contentFilePath = contentFilePath.TrimStart(
System.IO.Path.DirectorySeparatorChar);
}
else
{
//do nothing
}
contentFilePath = System.IO.Path.Combine(rootFolder, contentFilePath);
//contentFilePath = System.IO.Path.Combine(rootFolder, contentFilePath);
//Check for the folder already exists. If not then create that folder
if (System.IO.Directory.Exists(
System.IO.Path.GetDirectoryName(contentFilePath)) != true)
{
System.IO.Directory.CreateDirectory(
System.IO.Path.GetDirectoryName(contentFilePath));
}
else
{
//do nothing
}
System.IO.FileStream newFileStream =
System.IO.File.Create( contentFilePath );
newFileStream.Close();
byte[] content = new byte[contentFile.GetStream().Length];
contentFile.GetStream().Read(content, 0, content.Length );
System.IO.File.WriteAllBytes(contentFilePath, content);
}
#endregion
protected DialogResult
showMessage(string message,MessageBoxButtons button)
{
return MessageBox.Show (message, ".Net Zip / UnZip Tool",
button, MessageBoxIcon.Information );
}
} // End of the Class
/// <summary>
/// Definition of File Node class
/// </summary>
public class FileNode : TreeNode
{
//Define Enum for the type in which file is represented
//within the Tree Node. This is needed in case user
//want to view the file from the Tree view.
public enum enumFileStorageType
{ enmPhysicalFile, enmTextStream, enmUnKnown }
protected enumFileStorageType _fileStorageType =
enumFileStorageType.enmUnKnown;
public FileNode()
{ }
public FileNode(string key)
: base(key)
{ base.Name = key; }
/// <summary>
/// Returns Storage Type of this node
/// </summary>
public enumFileStorageType fileStorageType
{
get
{
return _fileStorageType;
}
set
{
_fileStorageType = value;
}
}
}
/// <summary>
/// Definition of Folder Node class
/// </summary>
public class FolderNode : TreeNode
{
public FolderNode()
{ }
public FolderNode(string key)
: base(key)
{ base.Name = key; }
}
}
关注点
有几件事需要知道
- 使用
Packaging.ZipPackage
创建 Zip 文件将创建一个“[Content_Types].xml”文件。 这定义了 zip 文件的内容和文件扩展名的映射。 - 我们在 Zip 文件中添加的文件名称中不能有空格。 目前,此工具将任何空格替换为下划线 (“_”) 字符。