我相信我們都很熟悉壓縮檔,並且瞭解較新的作業系統(Windows XP及更高版本)有能力使用它們之中的Zip檔。不過,你是否知道,如果你在使用這些更高版本的作業系統,你可以簡單地使用Windows Shell User Interface來程式設計使用Zip檔而不需要任何協力廠商產品?
Microsoft Windows使用者介面具有大量不同的物件使得使用者更加靈活。其中最大量的物件是在電腦磁片上存放的資料夾和檔,Windows Shell提供了一個相容的方式來訪問這些物件。
Shell物件展示Windows Shell中的物件。Shell物件所暴露的方法可以被用來做以下事情:
打開、探索和流覽資料夾。
最小化、恢復、層疊或平鋪打開視窗。
啟動控制台應用程式。
顯示系統對話方塊。
你大概熟悉你從Start功能表和工作列的快顯功能表中可以訪問的命令:所有這些功能都是通過Shell物件暴露出來的。
正如你可以想像,Windows Shell是一個龐大而複雜的議題,而我只將討論其中的一小部分。
什麼是Zip 檔?
一個ZIP檔包含一個或多個被壓縮了的檔以減小檔案大小(儘管檔案格式也使得檔可以存儲為原樣)。ZIP檔案格式允許使用一些不同的壓縮演算法,主流方法(以及Windows所使用的)是Deflate方法。
在某種程度上,叫做「Zip檔」是不正確的:從Windows Shell物件的角度來看。對於Windows來說,一個Zip檔實際上和一個資料夾沒有什麼不同,因為它可以包含多個檔。事實上,如圖1所顯示的,當你按右鍵一個檔並選擇Send To時,Windows Shell實際上顯示將這個檔案壓縮的選項為「Compressed (zipped) Folder」。
圖1:Send To功能表——Windows Shell 提供了一個選項「Compressed (zipped) Folder」
因為對於Windows Shell來說,它僅僅是一個資料夾,你可以使用Shell 物件的NameSpace方法來創建一個指向Zip檔內容的資料夾物件,就像它可以指向任何其它資料夾的內容一樣。
結果顯示,使得Windows Shell將一個Zip檔看做是一個資料夾的原因是在檔一開始所存在的那特殊的22個位元組的「指紋」。這22個位元組包括下面的ASCII字元:Chr$(80) & Chr$(75) & Chr$(5) & Chr$(6) & String(18, 0)。
將一個新檔指定為一個Zip 檔所需要的代碼就如示例1所示。



Private Sub InitializeZipFile( _
ZipFile As String _
)
Dim intFile As Integer
If Len(Dir(ZipFile)) > 0 Then
Kill ZipFile
End If
intFile = FreeFile
Open ZipFile For Output As #intFile
Print #intFile, Chr$(80) & Chr$(75) & _
Chr$(5) & Chr$(6) & String(18, 0)
Close #intFile
End Sub 示例 1 – 將一個空檔標明為一個Zip檔所需的代碼
這個代碼首先檢查這個檔是否存在,如果它存在那麼就刪除它。然後它使用Open語句來啟動輸出到檔(因此創建這個檔),以及Print語句給它編寫這22個字元的簽名。
添加到一個Zip檔
要創建一個Zip檔並給它添加一個檔,那麼這需要你如同所示地初始化這個Zip檔。然後你具現化Shell應用程式的一個實例,並使用Shell物件的NameSpace方法來創建一個Folder物件。當你創建了這個Folder物件,你就使用它的CopyHere方法來添加檔到那個Zip檔。這個代碼如示例2所示。



Sub AddFilesToZip( _
ZipFile As String, _
FileToAdd As String _
)
Dim objShell As Object
Dim varZipFile As Variant
If Len(Dir(FileToAdd)) > 0 Then
Call InitializeZipFile(ZipFile)
Set objShell = _
CreateObject("Shell.Application")
varZipFile = ZipFile
objShell.NameSpace(varZipFile).CopyHere _
(FileToAdd)
Do Until _
objShell.NameSpace(varZipFile).Items.Count _
>= 1
Call GoToSleep(100)
Loop
End If
End Sub 示例 2 – 添加一個檔到一個新的Zip檔所需的代碼
在這個代碼中引入varZipFIle的原因是zip檔的名稱必須存儲在一個變數中以便將它作為NameSpace來使用。如果你嘗試使用一個字串變數來替代,那麼你會得到一個錯誤91(「Object variable or With block variable not set」)。
你可能想瞭解在這個代碼中對GoToSleep的引用。GoToSleep是一小部分代碼,它使用Sleep API來暫停執行所指定的毫秒數,然後繼續執行,(如示例3所示)。包含它的原因是取決於要被添加的檔案大小,壓縮會佔用可觀的時間。實際上,它就是一個組合來確保我們一直等到壓縮完成。



Private Declare Sub Sleep Lib "kernel32" ( _
ByVal dwMilliseconds As Long _
)
Sub GoToSleep(TimeInMilliSec As Long)
If TimeInMilliSec > 0 Then
Call Sleep(TimeInMilliSec)
End If
End Sub
 
添加多個檔到Zip檔也是很容易的。例如,如果你想添加某個給定資料夾下的所有檔到你的Zip檔中,你可以使用Dir函數來獲取給定資料夾下每個檔的細節。當你瞭解了每個檔,你可以添加每個檔到這個Zip檔。示例4顯示了為了這麼做對示例2中的代碼所需做的修改。(注意,這沒有在子資料夾下添加檔)


Sub AddFolderToZip( _
ZipFile As String, _
FolderToAdd As String _
)
Dim objShell As Object
Dim lngFilesAdded As Long
Dim strFile As String
Dim varZipFile As Variant
Call InitializeZipFile(ZipFile)
Set objShell = _
CreateObject("Shell.Application")
varZipFile = ZipFile
If Right$(FolderToAdd, 1) <> "\" Then
FolderToAdd = FolderToAdd & "\"
End If
strFile = Dir(FolderToAdd & "*.*")
Do While Len(Dir(strFile)) > 0
objShell.NameSpace(varZipFile).CopyHere _
(FolderToAdd & strFile)
lngFilesAdded = lngFilesAdded + 1
Do Until _
objShell.NameSpace(varZipFile).Items.Count _
>= lngFilesAdded
Call GoToSleep(100)
Loop
strFile = Dir()
Loop
End Sub 示例 4 –添加一個資料夾下所有檔到一個新的Zip檔中所需的代碼
實際上,沒必要每次都使用一個新的Zip檔。示例5顯示了怎樣改變示例2來使用已存在的Zip檔。
Sub AddFilesToZip( _
ZipFile As String, _
FileToAdd As String _
)
Dim objShell As Object
Dim varZipFile As Variant
If Len(Dir(FileToAdd)) > 0 Then
If Len(Dir(ZipFile)) > 0 Then
If FileLen(ZipFile) = 0 Then
Call InitializeZipFile(ZipFile)
End If
Else
Call InitializeZipFile(ZipFile)
End If
Set objShell = _
CreateObject("Shell.Application")
varZipFile = ZipFile
objShell.NameSpace(varZipFile).CopyHere _
(FileToAdd)
Do Until _
objShell.NameSpace(varZipFile).Items.Count _
>= 1
Call GoToSleep(100)
Loop
End If
End Sub 示例 5 – 添加一個檔到一個新的或已存在的Zip檔中所需的代碼
查詢一個Zip檔
因為如同前面所提到的,Zip檔被Windows Shell當作是一個Folder,而且直接列出它內部所包含的檔:Folder物件的GetDetailsOf方法將提供給你你所需要的資訊。在示例6中所顯示的代碼將每個檔的細節寫到Immediate視窗中。


Sub ListFilesInZip( _
ZipFile As String _
)
Dim objShell As Object
Dim varFileName As Object
Dim varNameOfZipFile As Variant
If Len(Dir(ZipFile)) > 0 Then
Set objShell = _
CreateObject("Shell.Application")
varNameOfZipFile = ZipFile
Debug.Print _
"Details contained in " & ZipFile & vbCrLf
For Each varFileName In _
objShell.NameSpace(varNameOfZipFile).Items
With objShell.NameSpace(varNameOfZipFile)
Debug.Print "Name = " & _
.getdetailsof(varFileName, 0)
Debug.Print "Type = " & _
.getdetailsof(varFileName, 1)
Debug.Print "Last Modified = " & _
.getdetailsof(varFileName, 7)
Debug.Print "Unpacked Size = " & _
.getdetailsof(varFileName, 5)
Debug.Print "Packed Size = " & _
.getdetailsof(varFileName, 2)
Debug.Print "Ratio = " & _
.getdetailsof(varFileName, 6)
Debug.Print "CRC = " & _
.getdetailsof(varFileName, 8)
Debug.Print _
vbCrLf & String(20, "-") & vbCrLf
End With
Next varFileName
Set objShell = Nothing
End If
End Sub 示例 6 – 列出一個Zip檔中所包含檔的細節的代碼
 
從一個Zip 檔中提取
將檔提取到一個已知的位置也是很直接的。你可以具現化一個Folder物件展示你希望這些檔解壓到的目的地,然後使用CopyHere方法將這些檔從這個Zip檔案複製到這個位置。示例7介紹這一點。


Sub UnzipFilesToFolder( _
ZipFile As String, _
DestFolder As String _
)
Dim objShell As Object
Dim varDestFolder As Variant
Dim varZipFile As Variant
If Len(Dir(DestFolder, vbDirectory)) > 0 _
And Len(Dir(ZipFile)) > 0 Then
Set objShell = _
CreateObject("Shell.Application")
varDestFolder = DestFolder
varZipFile = ZipFile
objShell.Namespace(varDestFolder).CopyHere _
objShell.Namespace(varZipFile).items
Set objShell = Nothing
End If
End Sub 示例 7 – 解壓一個Zip檔中的所有檔的代碼
要獲得更高的細微性,你可以使用示例6中所顯示的技術來獲得這個Zip檔中所包含的檔的細節,然後使用你想使用CopyHere方法來解壓的特定檔的名稱。如果你只想解壓一個特定檔,那麼你替換這行代碼


objShell.Namespace(varDestFolder).CopyHere _
objShell.Namespace(varZipFile).items
objShell.Namespace(varDestFolder).CopyHere _
objShell.Namespace(varZipFile)._
items.Item(strFile) 這裡strFile包含要解壓的檔的名稱。
但是,似乎沒有從Zip檔刪除檔的方法(你需要創建一個新的Zip檔,從已有的Zip檔案複製你不想刪除的檔到這個新Zip檔中,刪除原來的Zip檔然後重命名這個新的Zip檔)。但是,如果你想做的是添加從你的應用程式內部壓縮檔的能力(也許因為你想將它們作為附件發送郵件),那麼這個技術很容易添加。
使用資料庫
這篇文章所使用的資料庫具有兩個表單。
一個表單(frmAddToZip)使得你可以指定一個檔,其它檔應該壓縮進這個檔,並指定哪個或哪些檔應該被壓縮進這個檔。我包含了調用標準Windows File Open對話方塊來讓你選擇Zip檔(順便說一下,這個不是必須已存在的)的代碼,或者你可以簡單地輸入檔案名稱到文字方塊中。(你可以通過點擊文字方塊右邊的按鈕或通過按兩下文字方塊本身來調用這個對話方塊)。不過要選擇要添加到這個Zip檔中的檔,你必須使用File Open對話方塊(你可以通過點擊大文字方塊右邊的按鈕或通過按兩下文字方塊本身來啟動這個對話方塊)。看起來「Files To Add」框是一個清單方塊,但是它只是一個文字方塊,各項被一個回車/換行組合分隔開。(這就是為什麼我不確定如果你簡單地將檔案名稱輸入這個框中它是否起作用)。
另一個表單(frmZipFileDetails)允許你指定一個zip檔。像以前一樣,你可以輸入這個檔的名稱到這個文字方塊中,或者你可以通過點擊文字方塊右邊的按鈕或通過按兩下文字方塊本身來調用標準Windows File Open對話方塊。(如果你輸入名稱,當你完成時你需要點擊Enter以便調用AfterUpdate事件)。當你提供了這個zip檔的路徑,這個zip檔中的檔的細節將顯示在下面的List View控制中。如果你還指定解壓這個檔的目的檔案夾(通過在文字方塊中輸入或通過使用按鈕或按兩下來調用標準Windows Browse Folder對話方塊),你將可以選擇解壓所有檔到這個位址。
注意事項
正如我在文章中所提到的,「ZIP檔案格式允許使用一些不同的壓縮演算法,主流方法(以及Windows所使用的)是Deflate方法。」我發現有幾個檔我對其使用了frmZipFileDetails,但在frmZipFileDetails中提供的技術沒有顯示其中檔的所有細節。我覺得這是因為它們是使用一個不同的技術而不是Deflate方法來創建的。如果你發現這個表單對你不起作用,那麼使用一個不同的Zip檔試試。
創作者介紹
創作者 shadow 的頭像
shadow

資訊園

shadow 發表在 痞客邦 留言(0) 人氣()