Imports System.IO
Imports System.IO.Compression
Imports System.Threading
Imports ICSharpCode.SharpZipLib.Checksums
Imports ICSharpCode.SharpZipLib.Core
Imports ICSharpCode.SharpZipLib.Zip
Imports System.Text
Imports System.Runtime.InteropServices
Imports ICSharpCode.SharpZipLib.Zip.Compression.Streams
Imports Ionic.Zip
' To use this class, you must include a reference to ICSharpCode.SharpZipLib.dll
Public Class clsCompareLibs
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'''''''''''''''''''''''''''''''''''''''''''''''' Fast File system tools ''''''''''''''''''''''''''''''''''''''''''''''''''''
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Public Class FastFileSystemTools
Public Const FILE_ATTRIBUTE_DIRECTORY As Integer = &H10
<DllImport("kernel32.dll", CharSet:=CharSet.Auto)> _
Public Shared Function FindFirstFile(ByVal lpFileName As String, ByRef lpFindFileData As WIN32_FIND_DATA) As IntPtr
End Function
<DllImport("kernel32.dll")> _
Public Shared Function FindClose(ByVal hFindFile As IntPtr) As Boolean
End Function
<DllImport("kernel32.dll", CharSet:=CharSet.Auto)> _
Public Shared Function FindNextFile(ByVal hFindFile As IntPtr, ByRef lpFindFileData As WIN32_FIND_DATA) As Boolean
End Function
'Public Declare Function FindNextFile Lib "kernel32" Alias "FindNextFileA" (ByVal hFindFile As IntPtr, ByRef lpFindFileData As WIN32_FIND_DATA) As Boolean
' The CharSet must match the CharSet of the corresponding PInvoke signature
' Get file size like this:
' Dim FileSize As Long = ((nFileSizeHigh << 32&) Or nFileSizeLow)
' .dwFileAttributes = 16 is a directory. > 16 is a file.
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
Public Structure WIN32_FIND_DATA
Public dwFileAttributes As UInteger
Public ftCreationTime As System.Runtime.InteropServices.ComTypes.FILETIME
Public ftLastAccessTime As System.Runtime.InteropServices.ComTypes.FILETIME
Public ftLastWriteTime As System.Runtime.InteropServices.ComTypes.FILETIME
Public nFileSizeHigh As UInteger
Public nFileSizeLow As UInteger
Public dwReserved0 As UInteger
Public dwReserved1 As UInteger
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)> Public cFileName As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=14)> Public cAlternateFileName As String
End Structure
Public Class ShortFileInfo
Public name As String
Public length As Int64
Public attributes As UInteger
Public xtraData As Int32
Public Sub New(ByVal fileName As String, ByVal fileSize As Int64, ByVal attribs As UInteger)
name = fileName
length = fileSize
attributes = attribs
End Sub
Public Sub New(ByVal fileName As String)
name = fileName
length = FastFileSize(fileName, attributes)
End Sub
End Class
Public Shared Function FastFileSize(ByVal filePath As String, Optional ByRef attribs As UInteger = 0) As Int64
Dim attributes As New WIN32_FIND_DATA
Try
Dim handle As IntPtr = FindFirstFile(filePath, attributes)
attribs = attributes.dwFileAttributes
FindClose(handle)
Return ((attributes.nFileSizeHigh << 32&) Or attributes.nFileSizeLow)
Catch ex As Exception
Return -1
End Try
End Function
Public Function GetFoldersInFolder(ByVal path As String) As List(Of String)
Dim attributes As New WIN32_FIND_DATA
Dim pathList As New List(Of String)
Dim handle As IntPtr
Dim searchPath As String
Dim builder As New StringBuilder(path)
If path.Substring(path.Length - 1, 1) <> "\" Then
builder.Append("\")
End If
path = builder.ToString()
builder.Append("*")
searchPath = builder.ToString()
handle = FindFirstFile(searchPath, attributes)
If CBool(attributes.dwFileAttributes And FILE_ATTRIBUTE_DIRECTORY) Then
' It's a folder...
builder.Remove(0, builder.Length)
builder.Append(path)
builder.Append(attributes.cFileName)
pathList.Add(builder.ToString())
Else
' It's a file...
End If
While FindNextFile(handle, attributes)
If CBool(attributes.dwFileAttributes And FILE_ATTRIBUTE_DIRECTORY) Then
' Its a folder...
builder.Remove(0, builder.Length)
builder.Append(path)
builder.Append(attributes.cFileName)
pathList.Add(builder.ToString())
Else
' It's a file...
End If
End While
FindClose(handle)
Return pathList
End Function
Public Function GetFilesInFolder(ByVal path As String, _
Optional ByVal recourseSubdirectories As Boolean = False, _
Optional ByRef folderSize As Int64 = 0) As List(Of ShortFileInfo)
Dim attributes As New WIN32_FIND_DATA
Dim filesList As New List(Of ShortFileInfo)
Dim foldersList As New List(Of String)
Dim tmp As New List(Of ShortFileInfo)
Dim handle As IntPtr
Dim searchPath As String
Dim builder As New StringBuilder(path)
Dim fileSize As Int64 = 0
If path.Substring(path.Length - 1, 1) <> "\" Then
builder.Append("\")
End If
path = builder.ToString()
builder.Append("*")
searchPath = builder.ToString()
handle = FindFirstFile(searchPath, attributes)
If CBool(attributes.dwFileAttributes And FILE_ATTRIBUTE_DIRECTORY) Then
' It's a folder...
If attributes.cFileName <> "." AndAlso attributes.cFileName <> ".." Then
foldersList.Add(attributes.cFileName)
End If
Else
' Add if it's a file...
builder.Remove(0, builder.Length)
builder.Append(path)
builder.Append(attributes.cFileName)
fileSize = ((attributes.nFileSizeHigh << 32&) Or attributes.nFileSizeLow)
folderSize += fileSize
filesList.Add(New ShortFileInfo(builder.ToString(), fileSize, _
attributes.dwFileAttributes))
End If
While FindNextFile(handle, attributes)
If CBool(attributes.dwFileAttributes And FILE_ATTRIBUTE_DIRECTORY) Then
' Its a folder...
If attributes.cFileName <> "." AndAlso attributes.cFileName <> ".." Then
foldersList.Add(attributes.cFileName)
End If
Else
' Add if it's a file...
builder.Remove(0, builder.Length)
builder.Append(path)
builder.Append(attributes.cFileName)
fileSize = ((attributes.nFileSizeHigh << 32&) Or attributes.nFileSizeLow)
folderSize += fileSize
filesList.Add(New ShortFileInfo(builder.ToString(), fileSize, _
attributes.dwFileAttributes))
End If
End While
FindClose(handle)
If recourseSubdirectories Then
If foldersList.Count > 0 Then
For Each folder As String In foldersList
builder.Remove(0, builder.Length)
builder.Append(path)
builder.Append(folder)
tmp = GetFilesInFolder(builder.ToString(), True, folderSize)
If tmp.Count > 0 Then filesList.AddRange(tmp)
Next
End If
End If
Return filesList
End Function
End Class
Public Class ZipData
Public fileList As List(Of ShortEntry)
Public totalBytes As Int64
Public totalBytesCopied As Int64
Public currentFileLength As Int64
Public currentFileBytesCopied As Int64
Public currentFileName As String
Public cancel As Boolean
Public complete As Boolean
Public operationTitle As String
Public errorMessage As String
End Class
Public Delegate Sub ResultCallback(ByRef ZipData)
Private zipfilePath As String
Private errorMessage As String
Private accessFlags As ZipAccessFlags
Private theZipInputStream As ICSharpCode.SharpZipLib.Zip.ZipInputStream
Private theZipOutputStream As ICSharpCode.SharpZipLib.Zip.ZipOutputStream
Private ionicZip As Ionic.zip.ZipOutputStream
Private buff() As Byte
Private updateInterval As Int32
Private callBack As ResultCallback
Private running As Boolean
Private updateSyncObject As Object
Private fileList As List(Of ShortEntry)
Private totalBytes As Int64
Private totalBytesCopied As Int64
Private currentFileLength As Int64
Private currentFileBytesCopied As Int64
Private currentFileName As String
Private operationTitle As String
Private cancelOperation As Boolean
Private useDotNetZip As Boolean
Private compressionLevel As Integer
Private useZip64 As Boolean
Private password As String
Private inputStream As FileStream
Private outPutStream As FileStream
Public Enum ZipAccessFlags
Read
Write
Create ' create and write.
End Enum
Private Structure AddFileListComm
Public fileList As List(Of String)
Public recourseSubdirectories As Boolean
Public setIsRunningFlag As Boolean
End Structure
Public Structure ShortEntry
Public name As String
Public size As Int64
Public index As Integer
End Structure
Private Structure MultiExtractComm
Public entries As List(Of ShortEntry)
Public targetFiolder As String
Public setIsRunningFlag As Boolean
Public justNames As Boolean
End Structure
Public ReadOnly Property GetErrorMessage() As String
Get
Return errorMessage
End Get
End Property
Public Sub Cancel()
cancelOperation = True
End Sub
Public ReadOnly Property IsRunning()
Get
Return running
End Get
End Property
Public Sub New(ByVal _zipFilePath As String, _accessflags As ZipAccessFlags, _
Optional bufferSize As Integer = (1024 * 256), _
Optional ByVal _useDotNetZip As Boolean = False, _
Optional ByVal _compressionLevel_0_to_9 As Integer = 0, _
Optional ByVal _useZip64 As Boolean = False, _
Optional ByVal _password As String = "", _
Optional ByVal _updateIntervalMilliseconds As Int32 = 100, _
Optional ByRef _callback As ResultCallback = Nothing)
If _compressionLevel_0_to_9 < 0 then _compressionLevel_0_to_9 = 0
If _compressionLevel_0_to_9 > 9 then _compressionLevel_0_to_9 = 9
accessFlags = _accessflags
zipfilePath = _zipFilePath
callBack = _callback
updateInterval = _updateIntervalMilliseconds
running = False
updateSyncObject = New Object
cancelOperation = False
useDotNetZip = _useDotNetZip
compressionLevel = _compressionLevel_0_to_9
password = _password
useZip64 = _useZip64
ReDim buff(bufferSize)
Dim mode As FileMode = FileMode.Open
Dim options As FileOptions = FileOptions.SequentialScan
'If unbuffered Then options = FileOptions.WriteThrough Or FileOptions.SequentialScan
' No error handling - we want any exceptions thrown.
If accessFlags = ZipAccessFlags.Read Then
inputStream = New FileStream(zipfilePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.SequentialScan)
theZipInputStream = New ICSharpCode.SharpZipLib.Zip.ZipInputStream(inputStream)
theZipInputStream.IsStreamOwner = True
Exit Sub
End If
If accessFlags = ZipAccessFlags.Create Then
mode = FileMode.Create
accessFlags = ZipAccessFlags.Write
End If
If accessFlags = ZipAccessFlags.Write Then
outPutStream = New FileStream(zipfilePath, mode, FileAccess.Write, FileShare.None, 4096, options)
Exit Sub
End If
End Sub
Private Sub Monitor()
Dim updateData As New ZipData
updateData.cancel = False
Do While running
Thread.Sleep(updateInterval)
With updateData
SyncLock updateSyncObject
.totalBytes = totalBytes
.totalBytesCopied = totalBytesCopied
.currentFileLength = currentFileLength
.currentFileBytesCopied = currentFileBytesCopied
.fileList = fileList
.currentFileName = currentFileName
.operationTitle = operationTitle
.errorMessage = errorMessage
.complete = False
.cancel = cancelOperation
End SyncLock
End With
If callBack IsNot Nothing Then callBack(updateData)
If Not cancelOperation AndAlso updateData.cancel Then cancelOperation = True
Loop
With updateData
SyncLock updateSyncObject
.totalBytes = totalBytes
.totalBytesCopied = totalBytesCopied
.currentFileLength = currentFileLength
.currentFileBytesCopied = currentFileBytesCopied
.fileList = fileList
.currentFileName = currentFileName
.operationTitle = operationTitle
.errorMessage = errorMessage
.complete = True
.cancel = cancelOperation
End SyncLock
End With
If callBack IsNot Nothing Then callBack(updateData)
End Sub
Public Sub Close()
If accessFlags = ZipAccessFlags.Read Then
Try
theZipInputStream.Close()
Catch ex As Exception
End Try
End If
If accessFlags = ZipAccessFlags.Write Then
Try
'theZipOutputStream.Finish()
Catch ex As Exception
End Try
Try
theZipOutputStream.Close()
Catch ex As Exception
End Try
End If
buff = Nothing
GC.Collect()
GC.GetTotalMemory(True)
End Sub
Public Function GetZipEntries() As Boolean
If accessFlags = ZipAccessFlags.Write Then Return False
If running Then
errorMessage = "An operation is already running."
Return False
End If
running = True
Dim getZipEntriesbgWorker As New Thread(AddressOf GetZipEntriesBackgroundWorker) With { _
.IsBackground = True
}
getZipEntriesbgWorker.Start()
Return True
End Function
Private Sub GetZipEntriesBackgroundWorker()
Dim index As Integer = 0
Dim callBackData As New ZipData With { _
.fileList = New List(Of ShortEntry),
.currentFileName = "",
.totalBytes = -1,
.totalBytesCopied = -1,
.currentFileLength = -1,
.currentFileBytesCopied = -1,
.operationTitle = "Listing zip entries..."
}
callBack(callBackData)
Try
If useDotNetZip Then
Using zip As ionic.zip.ZipFile = New ionic.zip.ZipFile(inputStream.Name)
For Each entry as ionic.zip.ZipEntry In zip.Entries
callBackData.fileList.Add(New ShortEntry With { _
.name = entry.FileName,
.size = entry.UncompressedSize,
.index = index
})
index += 1
Next
End Using
Else
Using zip As New ICSharpCode.SharpZipLib.Zip.ZipFile(inputStream)
Dim entry As ICSharpCode.SharpZipLib.Zip.ZipEntry
For count As Integer = 0 To zip.Count - 1
entry = zip.EntryByIndex(count)
callBackData.fileList.Add(New ShortEntry With { _
.name = entry.Name,
.size = entry.Size,
.index = count
})
Next
End Using
End If
Catch ex As Exception
errorMessage = "Could not get entry list. The error returned is: " & ex.Message
callBackData.errorMessage = errorMessage
End Try
callBackData.operationTitle = "Complete."
If callBackData.fileList.Count < 1 AndAlso errorMessage = "" Then
callBackData.fileList.Add(New ShortEntry With { _
.name = "This is an empty zip file.",
.size = 0,
.index = -1
})
End If
callBack(callBackData)
running = False
End Sub
Public Function Extract(ByVal zippedEntryName As String, _
ByVal targetFolder As String) As Boolean
If accessFlags = ZipAccessFlags.Write Then Return False
Dim entry As New List(Of ShortEntry)
entry.Add(New ShortEntry With { _
.name = zippedEntryName
})
running = True
Dim extractFileBgWorker As New Thread(AddressOf ExtractFileBackgroundWorker)
extractFileBgWorker.Start(New MultiExtractComm With { _
.entries = entry,
.targetFiolder = targetFolder,
.setIsRunningFlag = True,
.justNames = True
})
operationTitle = "Extracting"
Dim monitorThread As New Thread(AddressOf Monitor) With { _
.IsBackground = True,
.Name = "Zip Monitor"
}
monitorThread.Start()
Return True
End Function
Public Function Extract(ByVal zippedEntryNames As list(Of String), _
ByVal targetFolder As String)
If accessFlags = ZipAccessFlags.Write Then Return False
Dim entries As New List(Of ShortEntry)
For Each name As String In zippedEntryNames
entries.Add(New ShortEntry With { _
.name = name
})
Next
running = True
Dim extractFilesBgWorker As New Thread(AddressOf ExtractFileBackgroundWorker)
extractFilesBgWorker.Start(New MultiExtractComm With { _
.entries = entries,
.targetFiolder = targetFolder,
.setIsRunningFlag = True,
.justNames = True
})
operationTitle = "Extracting"
Dim monitorThread As New Thread(AddressOf Monitor) With { _
.IsBackground = True,
.Name = "Zip Monitor"
}
monitorThread.Start()
Return True
End Function
Public Function Extract(ByVal zippedEntryNames As List(Of ShortEntry), _
ByVal targetFolder As String)
If accessFlags = ZipAccessFlags.Write Then Return False
running = True
Dim extractFilesBgWorker As New Thread(AddressOf ExtractFileBackgroundWorker)
extractFilesBgWorker.Start(New MultiExtractComm With { _
.entries = zippedEntryNames,
.targetFiolder = targetFolder,
.setIsRunningFlag = True
})
operationTitle = "Extracting"
Dim monitorThread As New Thread(AddressOf Monitor) With { _
.IsBackground = True,
.Name = "Zip Monitor"
}
monitorThread.Start()
Return True
End Function
Private Sub ExtractFileBackgroundWorker(ByVal _comm As Object)
Dim comm As MultiExtractComm = DirectCast(_comm, MultiExtractComm)
Dim bytesRead As Long
Dim targetPath As String
Dim zippedEntries As New List(Of ShortEntry)
Dim tmpName As String
Dim tmpSize As Int64
Dim entryCollection As New List(Of Integer)
Dim index As Integer = 0
zippedEntries.AddRange(comm.entries)
targetPath = comm.targetFiolder
totalBytesCopied = 0
currentFileBytesCopied = 0
totalBytes = 0
currentFileName = ""
operationTitle = "Calculating total job size..."
If useDotNetZip Then
Dim Overwrite As ExtractExistingFileAction = ExtractExistingFileAction.OverwriteSilently
Dim ZipToUnpack As String = inputStream.Name
Dim UnpackDirectory As String = comm.targetFiolder
Using zip As ionic.zip.ZipFile = ionic.zip.ZipFile.Read(ZipToUnpack)
zip.BufferSize = 1024 * 128
AddHandler zip.ExtractProgress, AddressOf ExtractFileProgressCallback
Dim entriesInTheFile As New List(Of ionic.zip.ZipEntry)
entriesInTheFile.AddRange(zip.Entries)
If comm.justNames Then
' They only passed us names, as string. We need to
' create a collection of all the items to be extracted,
' and add up the file sizes.
For count As Integer = 0 to zip.Entries.Count -1
With entriesInTheFile.Item(count)
For Each fileToExtract As ShortEntry In zippedEntries
If fileToExtract.name = .FileName Then
'entryCollection.Add(count)
fileToExtract.size = .UncompressedSize
fileToExtract.index = count
totalBytes += .UncompressedSize
End If
Next
End With
Next
Else
' They gave us ShortEntries - we have the indexes of
' all the files to be restored, and the file sizes.
For Each entry As ShortEntry In zippedEntries
entryCollection.Add(entry.index)
totalBytes += entry.size
Next
End If
operationTitle = "Extracting with DotNetZip"
' here, we extract every entry, but we could extract conditionally,
' based on entry name, size, date, checkbox status, etc.
For Each entry As ionic.zip.ZipEntry In zip
entry.Password = password
If entry.FileName = zippedEntries.Item(0).name then
Try
entry.Extract(UnpackDirectory, Overwrite)
Catch ex As Exception
errorMessage = ex.Message
Exit For
End Try
zippedEntries.RemoveAt(0)
End If
If zippedEntries.Count = 0 then Exit For
If cancelOperation Then Exit For
Next
End Using
If Not cancelOperation Then _
currentFileBytesCopied = currentFileLength
If comm.setIsRunningFlag Then running = False
Else
' #ZipLib code...
Dim zip As New ICSharpCode.SharpZipLib.Zip.ZipFile(inputStream)
Dim longEntry As ICSharpCode.SharpZipLib.Zip.ZipEntry
If useZip64 Then zip.UseZip64 = True
If comm.justNames Then
' They only passed us names, as string. We need to
' create a collection of all the items to be extracted,
' and add up the file sizes.
For count = 0 To zip.Count - 1
With zip.EntryByIndex(count)
For Each entry As ShortEntry In zippedEntries
If entry.name = .Name Then
entryCollection.Add(count)
totalBytes += .Size
End If
Next
End With
Next
Else
' They gave us ShortEntries - we have the indexes of
' all the files to be restored, and the file sizes.
For Each entry As ShortEntry In zippedEntries
entryCollection.Add(entry.index)
totalBytes += entry.size
Next
End If
operationTitle = "Extracting with #ZipLib"
If entryCollection.Count < 1 Then
operationTitle = "Complete."
If comm.setIsRunningFlag Then running = False
Exit Sub
End If
For count = 0 To entryCollection.Count - 1
If entryCollection.Item(count) < 0 Then Continue For
longEntry = zip.EntryByIndex(entryCollection.Item(count))
With longEntry
tmpName = .Name
tmpSize = .Size
End With
Try
targetPath = comm.targetFiolder & "\" & tmpName ' theZipEntry.Name
targetPath = targetPath.Replace("/", "\")
currentFileBytesCopied = 0
currentFileLength = tmpSize
currentFileName = tmpName
If CreateFolders(targetPath) = False Then Throw New _
Exception("Could not create folders for " & targetPath)
Try
If File.Exists(targetPath) Then
File.SetAttributes(targetPath, IO.FileAttributes.Normal)
File.Delete(targetPath)
End If
Catch ex As Exception
Throw New Exception(ex.Message)
End Try
zip.Password = password
Using writer As FileStream = New FileStream(targetPath, FileMode.Create, FileAccess.Write, FileShare.None, 4096, FileOptions.SequentialScan)
If currentFileLength > 0 Then
Using localInputStream As Stream = zip.GetInputStream(longEntry)
bytesRead = 1
Do Until (bytesRead <= 0)
bytesRead = localInputStream.Read(buff, 0, buff.Length)
writer.Write(buff, 0, bytesRead)
currentFileBytesCopied += bytesRead
totalBytesCopied += bytesRead
If cancelOperation Then Exit For
Loop
End Using
End If
End Using
Catch ex As Exception
' Catch these "Unexpected EOF" errors, and continue
If ex.message = "Unexpected EOF" Then
' Do nothing here...
Else
errorMessage = "Error: Could not create " & targetPath & ": " & ex.Message
If comm.setIsRunningFlag Then running = False
Exit Sub
End If
End Try
Next
End If
If comm.setIsRunningFlag Then running = False
End Sub
Public Function Add(ByVal fileOrFolderPath As String, _
Optional ByVal recourseSubDirectories As Boolean = True) As Boolean
If accessFlags = ZipAccessFlags.Read Then Return False
Dim thisFolder As New List(Of String)
thisFolder.Add(fileOrFolderPath)
If Directory.Exists(fileOrFolderPath) Or File.Exists(fileOrFolderPath) Then
running = True
Dim addFolderBgWorker As New Thread(AddressOf AddFileListBackgroundWorker)
addFolderBgWorker.Start(New AddFileListComm With { _
.fileList = thisFolder,
.recourseSubdirectories = recourseSubDirectories,
.setIsRunningFlag = True
})
Else
errorMessage = "" & fileOrFolderPath & " can not be found."
End If
operationTitle = "Zipping"
Dim monitorThread As New Thread(AddressOf Monitor) With { _
.IsBackground = True,
.Name = "Zip Monitor"
}
monitorThread.Start()
Return True
End Function
Public Function Add(ByVal filesAndFolders As List(Of String), _
Optional ByVal recourseSubDirectories As Boolean = True) As Boolean
If accessFlags = ZipAccessFlags.Read Then Return False
running = True
Dim addFolderBgWorker As New Thread(AddressOf AddFileListBackgroundWorker)
addFolderBgWorker.Start(New AddFileListComm With { _
.fileList = filesAndFolders,
.recourseSubdirectories = recourseSubDirectories,
.setIsRunningFlag = True
})
operationTitle = "Zipping"
Dim monitorThread As New Thread(AddressOf Monitor) With { _
.IsBackground = True,
.Name = "Zip Monitor"
}
monitorThread.Start()
Return True
End Function
Private Function AddFileListBackgroundWorker(ByVal _comm As Object) As Boolean
Dim comm As AddFileListComm = DirectCast(_comm, AddFileListComm)
Dim tools As New FastFileSystemTools
Dim files As List(Of FastFileSystemTools.ShortFileInfo)
Dim allFiles As New List(Of FastFileSystemTools.ShortFileInfo)
Dim folderSize As Int64 = 0
Dim bytesRead As Integer
Dim unNeededPortion As Int32 = 0
For Each item As String In comm.fileList
If Directory.Exists(item) Then
files = tools.GetFilesInFolder(item, comm.recourseSubdirectories, folderSize)
unNeededPortion = item.Trim.Length - GetLastFolderName(item).Length
For Each file In files
file.xtraData = unNeededPortion
Next
allFiles.AddRange(files)
totalBytes += folderSize
ElseIf File.Exists(item) Then
allFiles.Add(New FastFileSystemTools.ShortFileInfo(item))
With allFiles.Item(allFiles.Count - 1)
totalBytes += .length
.xtraData = .name.Length - Path.GetFileName(.name).Length
End With
End If
Next
If useDotNetZip Then
operationTitle += " with DotNetZip"
Dim bufferPairs As Integer = (4 * System.Environment.ProcessorCount)
outPutStream.Close
Using output As Ionic.Zip.ZipOutputStream = New Ionic.Zip.ZipOutputStream(outPutStream.Name)
output.Encryption = Ionic.Zip.EncryptionAlgorithm.None
output.CompressionLevel = compressionLevel
If compressionLevel < 1 then _
output.CompressionMethod = Ionic.zip.CompressionMethod.None
output.ParallelDeflateMaxBufferPairs = bufferPairs
If useZip64 then output.EnableZip64 = Ionic.zip.Zip64Option.AsNecessary
Dim entry As Ionic.zip.ZipEntry
For Each inputFile As FastFileSystemTools.ShortFileInfo In allFiles
entry = output.PutNextEntry(inputFile.name.Remove(0, inputFile.xtraData))
currentFileBytesCopied = 0
currentFileLength = inputFile.length
currentFileName = inputFile.name
If password <> "" Then
entry.Password = password
entry.CompressionLevel = compressionLevel
End If
If inputFile.length > 0 Then
If inputFile.length > (1024 * 1024) Then
output.ParallelDeflateThreshold = 0
Else
output.ParallelDeflateThreshold = -1
End If
Using input As FileStream = File.Open(inputFile.name, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
bytesRead = 1
Do While (bytesRead > 0)
bytesRead = input.Read(buff, 0, buff.Length)
output.Write(buff, 0, bytesRead)
currentFileBytesCopied += bytesRead
totalBytesCopied += bytesRead
If cancelOperation Then Exit For
Loop
End Using
End If
Next
End Using
Else
operationTitle += " with #ZipLib"
Using output As ICSharpCode.SharpZipLib.Zip.ZipOutputStream = New ICSharpCode.SharpZipLib.Zip.ZipOutputStream(outPutStream, buff.Length)
output.Password = password
output.IsStreamOwner = True
output.SetLevel(compressionLevel)
If useZip64 then output.UseZip64 = ICSharpCode.SharpZipLib.Zip.UseZip64.On
Dim entry As ICSharpCode.SharpZipLib.zip.ZipEntry
For Each inputFile As FastFileSystemTools.ShortFileInfo In allFiles
entry = New ICSharpCode.SharpZipLib.Zip.ZipEntry(inputFile.name.Remove(0, _
inputFile.xtraData).Replace("\", "/")) With { _
.Size = inputFile.length,
.DateTime = Now
}
output.PutNextEntry(entry)
currentFileBytesCopied = 0
currentFileLength = inputFile.length
currentFileName = inputFile.name
Using source as FileStream = New FileStream(inputFile.name, FileMode.Open, FileAccess.Read, _
FileShare.Read, buff.Length, FileOptions.SequentialScan)
bytesRead = 1
Do Until (bytesRead <= 0)
If cancelOperation Then
entry.Size = currentFileBytesCopied
output.CloseEntry
running = False
Return True
End If
bytesRead = source.Read(buff, 0, buff.Length)
output.Write(buff, 0, bytesRead)
currentFileBytesCopied += bytesRead
totalBytesCopied += bytesRead
Loop
End Using
Next
End Using
End If
running = False
Return True
End Function
Private Function GetLastFolderName(ByVal folderPath As String) As String
If folderPath.Substring(folderPath.Length - 1, 1) = "\" Then folderPath = folderPath.Remove(folderPath.Length - 1, 1)
For position As Int32 = (folderPath.Length - 1) To 0 Step -1
If folderPath.Substring(position, 1) = "\" Then
Return folderPath.Remove(0, position)
End If
Next
Return ""
End Function
Private Function CreateFolders(ByVal filePath As String) As Boolean
If Directory.Exists(Path.GetDirectoryName(filePath)) Then Return True
Try
Directory.CreateDirectory(Path.GetDirectoryName(filePath))
Return True
Catch ex As Exception
Return False
End Try
End Function
Private Sub ExtractFileProgressCallback(ByVal sender As Object, ByVal e As ExtractProgressEventArgs)
Static lastBytesTransfered As Int64 = 0
e.Cancel = cancelOperation
currentFileName = Path.GetFileName(e.CurrentEntry.FileName)
If e.BytesTransferred = 0 then lastBytesTransfered = 0
currentFileBytesCopied = e.BytesTransferred
currentFileLength = e.CurrentEntry.UncompressedSize
totalBytesCopied += e.BytesTransferred - lastBytesTransfered
lastBytesTransfered = e.BytesTransferred
End Sub
End Class