從ZIP文件解壓并抽取數(shù)據(jù) java.util.zip 包提供了數(shù)據(jù)壓縮和解壓縮的類。解壓ZIP文件實質是從輸入流中讀出數(shù)據(jù)。java.util.zip 包提供了讀取ZIP文件的ZipInputStream 類??梢韵袢魏纹渌斎肓髂菢觿?chuàng)建 ZipInputStream 。例如,下列代碼可用于創(chuàng)建輸入流,以從ZIP文件格式中讀出數(shù)據(jù): FileInputStream fis = new FileInputStream("figs.zip"); ZipInputStream zin = new ZipInputStream(new BufferedInputStream(fis)); 一旦打開ZIP輸入流,就可以使用getNextEntry 方法讀取zip條目,該方法返回ZipEntry 對象。如果到達文件末尾, getNextEntry 就會返回零值: ZipEntry entry; while((entry = zin.getNextEntry()) != null) { // extract data // open output streams } 現(xiàn)在創(chuàng)建解壓縮輸出流,如下: int BUFFER = 2048; FileOutputStream fos = new FileOutputStream(entry.getName()); BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER); 注意: 在此節(jié)代碼中,我們用BufferedOutputStream 代替了ZIPOutputStream 。 ZIPOutputStream 和 GZIPOutputStream 使用大小為 512 的內部緩沖。 BufferedOutputStream 的使用僅在緩沖的大小遠遠超過 512 時 (本例的設置為 2048)要予以調整。不過,在ZIPOutputStream 的情況下,當GZIPOutputStream 不許設置緩沖區(qū)大小時,可以將內部緩沖區(qū)大小指定為設計參數(shù)。 在本節(jié)代碼中,文件輸出流是使用條目的名稱創(chuàng)建的,該名稱可以使用 entry.getName 方法進行檢索。然后,源壓縮數(shù)據(jù)會讀寫到解壓流: while ((count = zin.read(data, 0, BUFFER)) != -1) { //System.out.write(x); dest.write(data, 0, count); } 最后,結束輸入與輸出流∶ dest.flush(); dest.close(); zin.close(); 代碼樣本 1 中的源程序介紹了如何從 ZIP 文件中解壓和提取文件。要測試 此樣本,可對類進行編譯,并通過傳遞 ZIP 格式的已壓縮文件來進行運行: prompt> java UnZip somefile.zip 注意,somefile.zip 可以是任何ZIP兼容工具,如WinZip,創(chuàng)建的ZIP文件。 代碼樣本 1: UnZip.java import java.io.*; import java.util.zip.*; public class UnZip { final int BUFFER = 2048; public static void main (String argv[]) { try { BufferedOutputStream dest = null; FileInputStream fis = new FileInputStream(argv[0]); ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fis)); ZipEntry entry; while((entry = zis.getNextEntry()) != null) { System.out.println("Extracting: " +entry); int count; byte data[] = new byte[BUFFER]; // write the files to the disk FileOutputStream fos = new FileOutputStream(entry.getName()); dest = new BufferedOutputStream(fos, BUFFER); while ((count = zis.read(data, 0, BUFFER)) != -1) { dest.write(data, 0, count); } dest.flush(); dest.close(); } zis.close(); } catch(Exception e) { e.printStackTrace(); } } } 重要的是,要注意ZipInputStream 類是連續(xù)地讀取ZIP文件的。不過,類ZipFile 使用內部隨機存取文件讀取ZIP文件的內容,所以不必連續(xù)地讀取ZIP文件的條目。 注意: ZIPInputStream 和ZipFile 間的另一個基本區(qū)別是在高速緩存方面。在結合使用ZipInputStream 和 FileInputStream 讀取文件時,Zip條目沒有進行高速緩存。不過,如果文件是用ZipFile(fileName) 打開的,然后在內部進行高速緩存,那么,在ZipFile(fileName) 被再次調用時,該文件僅僅被打開一次。高速緩存值應用在第二次打開時。如果使用的是 UNIX,則值得注意的是,使用ZipFile 打開的全部ZIP文件都是內存映射的,因此ZipFile 的性能優(yōu)越于ZipInputStream 。不過,如果相同ZIP文件的內容在程序執(zhí)行期間要經(jīng)常地進行更改和重新加載,那么使用ZipInputStream 效果更好。 下面是 ZIP 文件使用ZipFile 類進行解壓的方式: - 創(chuàng)建
ZipFile 對象,方式是將待讀取的ZIP文件指定為字符串文件名或 File 對象。
ZipFile zipfile = new ZipFile("figs.zip"); - 使用條目方法,返回
Enumeration 對象,以循環(huán)通過文件全部的ZipEntry 對象: while(e.hasMoreElements()) { entry = (ZipEntry) e.nextElement(); // read contents and save them } - 通過將
ZipEntry 傳遞到getInputStream 的方式,讀取 ZIP 文件內部具體的ZipEntry ,它將返回可以讀取條目內容的InputStream 對象: is = new BufferedInputStream(zipfile.getInputStream(entry));
- 檢索條目的文件名并創(chuàng)建輸出流,以便保存:
byte data[] = new byte[BUFFER]; FileOutputStream fos = new FileOutputStream(entry.getName()); dest = new BufferedOutputStream(fos, BUFFER); while ((count = is.read(data, 0, BUFFER)) != -1) { dest.write(data, 0, count); } - 最后關閉所有輸入與輸出流∶
dest.flush(); dest.close(); is.close(); 完整的源程序如代碼樣本2所示。為測試該類,請再次進行編譯和運行,方式是傳遞 ZIP 格式參數(shù)的文件。 prompt> java UnZip2 somefile.zip 代碼樣本2: UnZip2.java import java.io.*; import java.util.*; import java.util.zip.*; public class UnZip2 { static final int BUFFER = 2048; public static void main (String argv[]) { try { BufferedOutputStream dest = null; BufferedInputStream is = null; ZipEntry entry; ZipFile zipfile = new ZipFile(argv[0]); Enumeration e = zipfile.entries(); while(e.hasMoreElements()) { entry = (ZipEntry) e.nextElement(); System.out.println("Extracting: " +entry); is = new BufferedInputStream (zipfile.getInputStream(entry)); int count; byte data[] = new byte[BUFFER]; FileOutputStream fos = new FileOutputStream(entry.getName()); dest = new BufferedOutputStream(fos, BUFFER); while ((count = is.read(data, 0, BUFFER)) != -1) { dest.write(data, 0, count); } dest.flush(); dest.close(); is.close(); } } catch(Exception e) { e.printStackTrace(); } } } 壓縮和歸檔 ZIP 文件中的數(shù)據(jù) ZipOutputStream 可用于將數(shù)據(jù)壓縮到ZIP文件。 ZipOutputStream 以ZIP格式將數(shù)據(jù)寫入輸出流。創(chuàng)建ZIP文件的步驟很多。 - 第一步是創(chuàng)建
ZipOutputStream 對象,將向它傳遞希望寫入文件的輸出流。創(chuàng)建名為“myfigs.zip”的ZIP文件的方式是: FileOutputStream dest = new FileOutputStream("myfigs.zip"); ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest)); - 一旦創(chuàng)建了目標壓縮輸出流,下一步就是打開源數(shù)據(jù)文件。本例中的源數(shù)據(jù)文件在當前目錄中。列表命令用來獲取當前目錄文件的列表:
File f = new File("."); String files[] = f.list(); for (int i=0; i<files.length; i++) { System.out.println("Adding: "+files[i]); FileInputStream fi = new FileInputStream(files[i]); // create zip entry // add entries to ZIP file } 注意: 本代碼樣本能夠壓縮當前目錄中的所有文件。它不處理子目錄。作為訓練,您可以修改代碼樣本 3,以處理子目錄。
- 為被讀取的每個文件創(chuàng)建壓縮條目:
ZipEntry entry = new ZipEntry(files[i])) - 在向ZIP輸出流寫入數(shù)據(jù)之前,您必須首先使用
out.putNextEntry(entry); 方法安置壓縮條目對象∶ out.putNextEntry(entry); - 向ZIP 文件寫入數(shù)據(jù)∶
int count; while((count = origin.read(data, 0, BUFFER)) != -1) { out.write(data, 0, count); } - 最后,結束輸入與輸出流∶
origin.close(); out.close(); 完整的源程序如代碼樣本 3 所示。 代碼樣本3: Zip.java import java.io.*; import java.util.zip.*; public class Zip { static final int BUFFER = 2048; public static void main (String argv[]) { try { BufferedInputStream origin = null; FileOutputStream dest = new FileOutputStream("c:\\zip\\myfigs.zip"); ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest)); //out.setMethod(ZipOutputStream.DEFLATED); byte data[] = new byte[BUFFER]; // get a list of files from current directory File f = new File("."); String files[] = f.list(); for (int i=0; i<files.length; i++) { System.out.println("Adding: "+files[i]); FileInputStream fi = new FileInputStream(files[i]); origin = new BufferedInputStream(fi, BUFFER); ZipEntry entry = new ZipEntry(files[i]); out.putNextEntry(entry); int count; while((count = origin.read(data, 0, BUFFER)) != -1) { out.write(data, 0, count); } origin.close(); } out.close(); } catch(Exception e) { e.printStackTrace(); } } } 注意:條目可以添加到壓縮(DEFLATED)或未壓縮(STORED)表格中的 ZIP 文件里。setMethod 可用于設置存儲的方法。例如,將方法設置為 DEFLATED (壓縮),請使用: out.setMethod(ZipOutputStream.DEFLATED) ;將它設置為 STORED (非壓縮),請使用:out.setMethod ( ZipOutputStream.STORED) 。 |