Show a ZIP within a TreeView in WinForms (VB)
This app is a VB WinForms app that displays the contents of a ZIP file in a TreeView. Below is the code for the just the Form. The most interesting methods for building the TreeView are AddTreeNode() and FindNodeForTag(). The approach is to enumerate (For Each) the entries in the zip file, and for each one, add a node to the treeview, and any required node hierarchy according to the path of the ZipEntry. What is not shown is how to use the TreeView thus populated. One interesting possibility is to allow a right-click context menu popup, and extraction of a particular entry. This should be easy to achieve. The Tag property on each node defines the path of the ZipEntry, and this path can be used in the string indexer on the ZipFile instance. So in the onClick method for the context menu item, you can do zip(node.Tag).Extract(). To get a zip of the complete Visual Studio solution for this simple example, see here.
Imports Ionic.Zip
Imports System.Linq
Imports System.IO
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
PopulateTreeView()
End Sub
Private zip As Ionic.Zip.ZipFile
''' <summary>
''' Populates TreeView1 with the entries in the zipfile, named by TextBox1
''' </summary>
Private Sub PopulateTreeView()
Try
zip = ZipFile.Read(Me.TextBox1.Text)
Me.TreeView1.Nodes.Clear()
For Each e As ZipEntry In zip
AddTreeNode(e.FileName)
Next
Catch ex As Exception
'' eg, file does not exist, or access denied, etc
MessageBox.Show("Exception: " + ex.ToString(), _
"Exception during zip processing", _
MessageBoxButtons.OK, _
MessageBoxIcon.Exclamation)
Finally
If Not (zip Is Nothing) Then
zip.Dispose()
End If
End Try
End Sub
''' <summary>
''' Add a node to the Treeview, for the given ZipEntry name
''' </summary>
''' <param name="name">name of the ZipEntry</param>
''' <returns>the TreeNode added</returns>
''' <remarks>
''' <para>
''' Entries in a zip file exist in a "flat container space": there is a single container,
''' the zip file itself, that contains all entries. Even though each entry has a filename
''' attached to it, and that filename may include a hierarchial directory path, the entry is
''' always contained in the zipfile itself. Even though it is possible to include directory
''' entries in a zip file, those directory entries are not, themselves, containers - they do
''' not contain other zip entries.
''' </para>
''' <para>
''' This method overlays the zipentry, which exists only in a flat namespace, into a hierarchial
''' tree, creating that tree from the pathname on the entry. If the entry name is /a/b/c.txt,
''' then this method adds 3 nodes to the TreeView, one for each segment in the path.
''' </para>
''' <para>
''' The method is smart enough to find existing nodes matching subsegements of the path
''' for an entry.
''' </para>
''' </remarks>
Private Function AddTreeNode(ByVal name As String) As TreeNode
If (name.EndsWith("/")) Then
name = name.Substring(0, name.Length - 1)
End If
Dim node As TreeNode = FindNodeForTag(name, Me.TreeView1.Nodes)
If Not (node Is Nothing) Then
Return node
End If
Dim pnodeCollection As TreeNodeCollection
Dim parent As String = Path.GetDirectoryName(name)
If (parent = "") Then
pnodeCollection = Me.TreeView1.Nodes
Else
pnodeCollection = AddTreeNode(parent.Replace("\", "/")).Nodes
End If
node = New TreeNode
node.Text = Path.GetFileName(name)
node.Tag = name ' full path
pnodeCollection.Add(node)
Return node
End Function
''' <summary>
''' Returns the TreeNode for a given name
''' </summary>
''' <param name="name">name of the ZipEntry</param>
''' <param name="nodes">The TreeNodeCollection to search</param>
''' <returns>the matching TreeNode, or nothing if none exists</returns>
''' <remarks>
''' This method is used by AddTreeNode() to find existing nodes.
''' </remarks>
Private Function FindNodeForTag(ByVal name As String, ByRef nodes As TreeNodeCollection) As TreeNode
For Each node As TreeNode In nodes
If (name = node.Tag) Then
Return node
ElseIf (name.StartsWith(node.Tag + "/")) Then
Return FindNodeForTag(name, node.Nodes)
End If
Next
Return Nothing
End Function
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim openFileDialog1 As OpenFileDialog = New OpenFileDialog
openFileDialog1.InitialDirectory = Me.TextBox1.Text
openFileDialog1.Filter = "zip files|*.zip|EXE files|*.exe|All Files|*.*"
openFileDialog1.FilterIndex = 1
openFileDialog1.RestoreDirectory = True
If (openFileDialog1.ShowDialog() = DialogResult.OK) Then
Me.TextBox1.Text = openFileDialog1.FileName
If (System.IO.File.Exists(Me.TextBox1.Text)) Then
Button1_Click(sender, e)
End If
End If
End Sub
End Class
|