הערה
הגישה לדף זה מחייבת הרשאה. באפשרותך לנסות להיכנס או לשנות מדריכי כתובות.
הגישה לדף זה מחייבת הרשאה. באפשרותך לנסות לשנות מדריכי כתובות.
Question
Wednesday, January 22, 2014 5:37 AM
Hi,
I have files in a folder "test" and i want to make a zip of the contents(not the folder) and have that zip in the directory of the folder.
Sor far, all is well:
Dim curentDate As String = System.DateTime.Now.ToShortDateString
Dim gamepath As String = TextBox1.Text
Dim zipPath As String = gamepath + "backup" + curentDate + ".zip"
Dim extractPath As String = "gamepath"
'zip
ZipFile.CreateFromDirectory(gamepath, zipPath)
'extract
ZipFile.ExtractToDirectory(zipPath, extractPath)
But, how do I add a progress bar and a percentage label? I don't mind if the percentage has decimals as long as it's only to 2 decimal points.
Thanks so much,
David Wu
All replies (12)
Wednesday, January 22, 2014 8:10 PM ✅Answered
You'll have to extract each file individually so that you have a chance to update the progress bar. Keep in mind that the process is likely to occur much faster than the progressbar can actually update unless the archive is very large.
Here's a brief example of one way to do it:
'Add references to:
' System.IO.Compression
' System.IO.Compression.FileSystem
Imports System.IO
Imports System.IO.Compression
Public Class Form1
Friend ProgressBar1 As New ProgressBar
Friend WithEvents Button1 As New Button With {.Top = ProgressBar1.Height + 4}
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Controls.Add(ProgressBar1)
Controls.Add(Button1)
End Sub
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Button1.Enabled = False
Await ExtractAllAsync("c:\test\test.zip", "c:\test\test extract", ProgressBar1)
Button1.Enabled = True
End Sub
Private Async Function ExtractAllAsync(zipFilePath As String, extractPath As String, progress As ProgressBar) As Task
Try
Dim extractCount, skipCount, errorCount As Integer
Using archive As ZipArchive = ZipFile.OpenRead(zipFilePath)
progress.Minimum = 0
progress.Maximum = archive.Entries.Count
Await Task.Run(Sub()
Dim count As Integer = archive.Entries.Count
For i As Integer = 0 To count - 1
Try
Dim entry As ZipArchiveEntry = archive.Entries(i)
entry.ExtractToFile(Path.Combine(extractPath, entry.FullName))
extractCount += 1
Catch ioex As IOException
If ioex.Message.EndsWith("already exists.") Then
skipCount += 1
Else
errorCount += 1
End If
Catch ex As Exception
errorCount += 1
End Try
Invoke(Sub() progress.Value += 1)
'System.Threading.Thread.Sleep(100) 'might want delay to see progress animation better
Next
'System.Threading.Thread.Sleep(100)
End Sub)
End Using
MessageBox.Show(String.Format("Extracted {0} files, skipping {1} because they exist, with {2} errors.", extractCount, skipCount, errorCount), "Extraction Complete", MessageBoxButtons.OK, MessageBoxIcon.Information)
progress.Value = 0
Catch ex As Exception
MessageBox.Show(ex.Message, "Error Opening Zip File", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Function
End Class
Reed Kimble - "When you do things right, people won't be sure you've done anything at all"
Thursday, January 23, 2014 8:07 PM ✅Answered
Well I changed it by using some timers.
Although it seems to me that backgroundworkers are passing variables that were created in another thread information without crossthread issues. So I'm not sure why a background worker can pass a variable information but not a control information without a crossthread issue.
This code is pretty much in line with what Noodles LV proposed.
I'll post some images a bit later.
Option Strict On
' NOTE: Only works with .Net 4.5 or above. Compile to .Net 4.5 or above.
' Also crashes if you attempt to zip a shortcut.
Imports System.IO
Imports System.IO.Compression ' Add reference to this in Assemblies as well as a reference to System.IO.Compression.FileSystem I think.
Public Class Form1
' How to: Compress and Extract Files http://msdn.microsoft.com/en-us/library/ms404280(v=vs.110).aspx
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.CenterToScreen()
Me.BackColor = Color.PapayaWhip
Me.Text = "Zip and Unzip files using .Net 4.5 System.IO.Compression"
Button1.BackColor = Color.Lime
Button2.BackColor = Color.Lime
Button3.BackColor = Color.Lime
Button4.BackColor = Color.LightGray
Button4.Enabled = False
ProgressBar1.Minimum = 0
ProgressBar1.Maximum = 100
Label1.Text = "Waiting"
Label2.Text = "Waiting"
ListView1.MultiSelect = False
ListView1.GridLines = True
ListView1.LabelEdit = True
ListView1.UseCompatibleStateImageBehavior = False
ListView1.View = View.Details
ListView1.Sorting = SortOrder.Ascending
ListView1.Columns.Add("Files to be Zipped", 434, HorizontalAlignment.Left)
Timer1.Interval = 1
Timer2.Interval = 1
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Button1.Enabled = False
Button2.Enabled = False
Button3.Enabled = False
Button1.BackColor = Color.OrangeRed
Button2.BackColor = Color.LightGray
Button3.BackColor = Color.LightGray
Dim SFD As New SaveFileDialog
SFD.Title = "Create Zip file. Type in name (i.e. ZipFile), do not add .Zip extension."
SFD.InitialDirectory = "C:\Users\John\Desktop"
SFD.DefaultExt = ""
SFD.Filter = "Zip Files (*.Zip)|*.Zip"
If SFD.ShowDialog = Windows.Forms.DialogResult.OK Then
My.Computer.FileSystem.CreateDirectory(SFD.FileName.ToString.Replace(".Zip", ""))
ZipFile.CreateFromDirectory(SFD.FileName.ToString.Replace(".Zip", ""), SFD.FileName)
If My.Computer.FileSystem.DirectoryExists(SFD.FileName.ToString.Replace(".Zip", "")) Then
My.Computer.FileSystem.DeleteDirectory(SFD.FileName.ToString.Replace(".Zip", ""), FileIO.DeleteDirectoryOption.DeleteAllContents)
End If
End If
Button1.Enabled = True
Button2.Enabled = True
Button3.Enabled = True
Button1.BackColor = Color.Lime
Button2.BackColor = Color.Lime
Button3.BackColor = Color.Lime
End Sub
Dim FilesToZipSize As Integer = 0
Dim FileInfo() As String
Dim ZipFiletoUse As String = ""
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Button1.Enabled = False
Button2.Enabled = False
Button3.Enabled = False
Button1.BackColor = Color.LightGray
Button2.BackColor = Color.OrangeRed
Button3.BackColor = Color.LightGray
Dim OFD1 As New OpenFileDialog
OFD1.Title = "Select Zip file to use"
OFD1.InitialDirectory = "C:\Users\John\Desktop"
OFD1.Filter = "Zip Files (*.Zip)|*.Zip"
OFD1.Multiselect = False
Dim OFD2 As New OpenFileDialog
OFD2.Title = "Select files to Zip"
OFD2.Multiselect = True
OFD2.InitialDirectory = "C:\Users\John\Desktop"
OFD2.Filter = "All Files|*.*"
If OFD1.ShowDialog = Windows.Forms.DialogResult.OK Then
ZipFileToUse = OFD1.FileName
If OFD2.ShowDialog = Windows.Forms.DialogResult.OK Then
For Each Item In OFD2.FileNames
FilesToZipSize += CInt(FileLen(Item))
ListView1.Items.Add(Item)
Next
FileInfo = OFD2.FileNames
BGW1Active = True
Timer1.Start()
ProgressBar1.Value = 0
BackgroundWorker1.RunWorkerAsync()
End If
End If
End Sub
Dim ZipFolderToUnzipFilesFrom As String = ""
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Button1.Enabled = False
Button2.Enabled = False
Button3.Enabled = False
Button1.BackColor = Color.LightGray
Button2.BackColor = Color.LightGray
Button3.BackColor = Color.OrangeRed
CheckedListBox1.Items.Clear()
Dim OFD As New OpenFileDialog
OFD.Title = "Select Zip folder to use"
OFD.InitialDirectory = "C:\Users\John\Desktop"
OFD.Filter = "Zip Files (*.Zip)|*.Zip"
OFD.Multiselect = False
If OFD.ShowDialog = Windows.Forms.DialogResult.OK Then
ZipFolderToUnzipFilesFrom = OFD.FileName
Using archive As ZipArchive = ZipFile.OpenRead(OFD.FileName)
For Each entry As ZipArchiveEntry In archive.Entries
CheckedListBox1.Items.Add(entry.ToString)
Next
End Using
If CheckedListBox1.Items.Count = 0 Then
Button1.Enabled = True
Button2.Enabled = True
Button3.Enabled = True
Button1.BackColor = Color.Lime
Button2.BackColor = Color.Lime
Button3.BackColor = Color.Lime
End If
End If
End Sub
Private Sub CheckedListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles CheckedListBox1.SelectedIndexChanged
If CheckedListBox1.CheckedItems.Count > 0 Then
Button4.Enabled = True
Button4.BackColor = Color.Lime
End If
End Sub
Dim FolderToUnzipFilesTo As String = ""
Dim FilesToUnzipSize As Integer = 0
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
Button3.BackColor = Color.LightGray
If CheckedListBox1.CheckedItems.Count = 0 Then
Button1.Enabled = True
Button2.Enabled = True
Button3.Enabled = True
Button1.BackColor = Color.Lime
Button2.BackColor = Color.Lime
Else
Button4.Enabled = False
Button4.BackColor = Color.OrangeRed
Dim FBD As New FolderBrowserDialog
FBD.Description = "Select folder or create folder to unzip file(s) to"
FBD.RootFolder = Environment.SpecialFolder.Desktop
If FBD.ShowDialog = Windows.Forms.DialogResult.OK Then
FolderToUnzipFilesTo = FBD.SelectedPath
Using archive As ZipArchive = ZipFile.OpenRead(ZipFolderToUnzipFilesFrom)
For Each Item In CheckedListBox1.CheckedItems
For Each entry As ZipArchiveEntry In archive.Entries
If entry.FullName.ToString = Item.ToString Then
FilesToUnzipSize += CInt(entry.Length)
End If
Next
Next
End Using
BGW2Active = True
Timer2.Start()
ProgressBar1.Value = 0
BackgroundWorker2.RunWorkerAsync()
Else
Button1.Enabled = True
Button2.Enabled = True
Button3.Enabled = True
Button1.BackColor = Color.Lime
Button2.BackColor = Color.Lime
Button3.BackColor = Color.Lime
Button4.BackColor = Color.LightGray
End If
End If
End Sub
Dim BGW1Active As Boolean = False
Dim BGW1Percent As Integer = 0
Dim BGW1Item As String = ""
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
For Each Item In FileInfo
BGW1Item = Item
Using zipToOpen As FileStream = New FileStream(ZipFiletoUse, FileMode.Open)
Using archive As ZipArchive = New ZipArchive(zipToOpen, ZipArchiveMode.Update)
Dim TempSplit() As String
TempSplit = Item.Split("\"c)
Dim readmeEntry As ZipArchiveEntry = archive.CreateEntry(TempSplit(TempSplit.Count - 1))
Dim BlockSizeToRead As Integer = 4096
Dim Buffer As Byte() = New Byte(BlockSizeToRead - 1) {}
Using writer As Stream = readmeEntry.Open
Using Reader As FileStream = File.Open(Item, FileMode.Open)
Dim bytesRead As Integer, totalBytesRead As Integer, bytesMe = 0
While (InlineAssignHelper(bytesRead, Reader.Read(Buffer, 0, Buffer.Length - 1))) > 0
writer.Write(Buffer, 0, bytesRead)
totalBytesRead += bytesRead
BGW1Percent = CInt(totalBytesRead / FilesToZipSize * 100)
End While
End Using
End Using
End Using
End Using
Next
BGW1Active = False
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
If BGW1Active = True Then
ProgressBar1.Value = BGW1Percent
Label1.Text = "File being zipped is " & BGW1Item
Label2.Text = "Percent zipped is " & BGW1Percent.ToString & ChrW(37)
Else
Timer1.Stop()
Button1.Enabled = True
Button2.Enabled = True
Button3.Enabled = True
Button1.BackColor = Color.Lime
Button2.BackColor = Color.Lime
Button3.BackColor = Color.Lime
ListView1.Items.Clear()
Label1.Text = "Waiting"
Label2.Text = "Waiting"
ProgressBar1.Value = 0
FilesToZipSize = 0
BGW1Percent = 0
BGW1Item = ""
End If
End Sub
Dim BGW2Active As Boolean = False
Dim BGW2Percent As Integer = 0
Dim BGW2Item As String = ""
Private Sub BackgroundWorker2_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker2.DoWork
Using archive As ZipArchive = ZipFile.OpenRead(ZipFolderToUnzipFilesFrom)
For Each Item In CheckedListBox1.CheckedItems
For Each entry As ZipArchiveEntry In archive.Entries
If entry.FullName.ToString = Item.ToString Then
BGW2Item = Item.ToString
Using Reader As Stream = entry.Open
Using Writer As FileStream = File.Open(Path.Combine(FolderToUnzipFilesTo, Item.ToString), FileMode.OpenOrCreate)
Dim bytesWritten As Integer, totalBytesWritten As Integer, bytesMe = 0
Dim BlockSizeToWrite As Integer = 4096
Dim Buffer As Byte() = New Byte(BlockSizeToWrite - 1) {}
While (InlineAssignHelper(bytesWritten, Reader.Read(Buffer, 0, Buffer.Length - 1))) > 0
Writer.Write(Buffer, 0, bytesWritten)
totalBytesWritten += bytesWritten
BGW2Percent = CInt(totalBytesWritten / FilesToUnzipSize * 100)
End While
End Using
End Using
End If
Next
Next
End Using
BGW2Active = False
End Sub
Private Sub Timer2_Tick(sender As Object, e As EventArgs) Handles Timer2.Tick
If BGW2Active = True Then
ProgressBar1.Value = BGW2Percent
Label1.Text = "File being unzipped is " & BGW2Item
Label2.Text = "Percent unzipped is " & BGW2Percent.ToString & ChrW(37)
Else
Timer2.Stop()
Button1.Enabled = True
Button2.Enabled = True
Button3.Enabled = True
Button1.BackColor = Color.Lime
Button2.BackColor = Color.Lime
Button3.BackColor = Color.Lime
Button4.BackColor = Color.LightGray
CheckedListBox1.Items.Clear()
Label1.Text = "Waiting"
Label2.Text = "Waiting"
ProgressBar1.Value = 0
FilesToUnzipSize = 0
BGW2Percent = 0
BGW2Item = ""
End If
End Sub
Private Function InlineAssignHelper(Of T)(ByRef target As T, value As T) As T
target = value
Return value
End Function
End Class
Please BEWARE that I have NO EXPERIENCE and NO EXPERTISE and probably onset of DEMENTIA which may affect my answers! Also, I've been told by an expert, that when you post an image it clutters up the thread and mysteriously, over time, the link to the image will somehow become "unstable" or something to that effect. :) I can only surmise that is due to Global Warming of the threads.
Wednesday, January 22, 2014 7:19 AM | 1 vote
Hello,
for extraction and compression not provides progress method, If you want progress bar updating, Gets the total number of bytes that need to be compressed,, compress the files by whatever chunk size that you choose and then report progress at whatever level of detail that you wish.
if the reply help you mark it as your answer.
Free Managed .NET Word Component(Create, Modify, Convert & Print)
Wednesday, January 22, 2014 4:45 PM | 1 vote
I suppose you are using the ZipFile Class which is only available in .Net 4.5 (and later above .Net 4.5 I would guess).
I'm fairly certain that can be done but it will take a while to try it.
How to: Compress and Extract Files
Please BEWARE that I have NO EXPERIENCE and NO EXPERTISE and probably onset of DEMENTIA which may affect my answers! Also, I've been told by an expert, that when you post an image it clutters up the thread and mysteriously, over time, the link to the image will somehow become "unstable" or something to that effect. :) I can only surmise that is due to Global Warming of the threads.
Wednesday, January 22, 2014 7:34 PM
You could use the third-party DotNetZip Library. I haven't used it, but here is a thread asking about using a progress bar: Handle progress-bar.
HTH,
Andrew
Thursday, January 23, 2014 5:43 PM
@Mr.Monkeyboy
You should not post an example if you can't make it work without turning off cross-thread checking. That property exists solely for the VB6 upgrade wizard and should never be set on purpose.
Reed Kimble - "When you do things right, people won't be sure you've done anything at all"
Thursday, January 23, 2014 5:53 PM
@Mr.Monkeyboy
You should not post an example if you can't make it work without turning off cross-thread checking. That property exists solely for the VB6 upgrade wizard and should never be set on purpose.
Reed Kimble - "When you do things right, people won't be sure you've done anything at all"
O.K.
Please BEWARE that I have NO EXPERIENCE and NO EXPERTISE and probably onset of DEMENTIA which may affect my answers! Also, I've been told by an expert, that when you post an image it clutters up the thread and mysteriously, over time, the link to the image will somehow become "unstable" or something to that effect. :) I can only surmise that is due to Global Warming of the threads.
Thursday, January 23, 2014 6:02 PM
@Mr.Monkeyboy
You should not post an example if you can't make it work without turning off cross-thread checking. That property exists solely for the VB6 upgrade wizard and should never be set on purpose.
Reed Kimble - "When you do things right, people won't be sure you've done anything at all"
O.K.
Please BEWARE that I have NO EXPERIENCE and NO EXPERTISE and probably onset of DEMENTIA which may affect my answers! Also, I've been told by an expert, that when you post an image it clutters up the thread and mysteriously, over time, the link to the image will somehow become "unstable" or something to that effect. :) I can only surmise that is due to Global Warming of the threads.
Thank you.
To correct your sample, look inside of your DoWork routine(s) and anywhere you need to access a control member, either do so through ReportProgress or create a delegate method to do that work and Invoke the delegate. It is often easiest to use the generic ones like Me.Invoke(New Action(AddressOf mywork))
I'd be happy to help you understand the Action and Func delegates more if you'd like to start a thread on it.
Reed Kimble - "When you do things right, people won't be sure you've done anything at all"
Thursday, January 23, 2014 8:59 PM
You can pass variables between threads, so long as the object that the variable represents is not owned by a particular thread. When a control instance is created, it is owned by the thread that created it and cannot (should not) be directly access by another thread. If the variable is accessible from more than one thread, then you have to code carefully to avoid race conditions and deadlocks. You also have to be careful that you don't inadvertently reduce performance instead of increasing it.
The BackgroundWorker made things easier if you put all of the secondary thread operations in DoWork and only interact with the primary thread through ReportProgress.
But even the BackgroundWorker has been replaced in favor of using Await in VS2012+. I was a little late to adopt it because I hated 2012 lol but I'm in 2013 now and getting comfortable and getting used to Await has been at the top of my to-do list. It really does make async and multithreaded code much cleaner to write and read/debug.
Reed Kimble - "When you do things right, people won't be sure you've done anything at all"
Thursday, January 23, 2014 9:07 PM
I saw Await in your example you posted but as I'm unfamiliar with it I did not want to try it with all the other issues I was having just to get the code I posted to work. In fact Async code is not in my scope of knowledge at this moment in time. And probably not soon either.
Please BEWARE that I have NO EXPERIENCE and NO EXPERTISE and probably onset of DEMENTIA which may affect my answers! Also, I've been told by an expert, that when you post an image it clutters up the thread and mysteriously, over time, the link to the image will somehow become "unstable" or something to that effect. :) I can only surmise that is due to Global Warming of the threads.
Friday, January 24, 2014 11:03 PM
Images of example working.
Please BEWARE that I have NO EXPERIENCE and NO EXPERTISE and probably onset of DEMENTIA which may affect my answers! Also, I've been told by an expert, that when you post an image it clutters up the thread and mysteriously, over time, the link to the image will somehow become "unstable" or something to that effect. :) I can only surmise that is due to Global Warming of the threads.
Sunday, January 26, 2014 5:31 AM
Look here:
http://dotnetzip.codeplex.com/downloads/get/258014
and here
http://archive.msdn.microsoft.com/DotNetZip/Release/ProjectReleases.aspx?ReleaseId=3097
has everything you asked about