[關鍵詞]:ant,zip,unzip,Apache,壓縮,解壓,中文亂碼,ZipEntry
先前寫了一篇blog
《使用org.apache.tools.zip實現zip壓縮和解壓》,現對它進行了改進:找出了幾個Bug,修改了部分代碼,增加了注釋,添加了圖形界面,打了個可執行包,雙就可以運行了。源代碼如下,希望大家多提意見。
MyZip.java:
package myzip;
import java.io.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import myzip.AntZip;
/**
*界面類,調用AntZip類實現壓縮解壓功能。
*@version 2009-3-18
*@author Winty (wintys@gmail.com)
*/
public class MyZip{
public static void main(String[] args){
new MyZip(new AntZip());
}
public MyZip(AntZip zip){
this.zip = zip;
this.latestDir = new File(".");
buildUI();
}
public void buildUI(){
jframe = new JFrame();
jframe.setTitle("MyZip");
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setResizable(false);
jframe.setSize(230 , 150);
Dimension screen= Toolkit.getDefaultToolkit().getScreenSize();
jframe.setLocation((screen.width-jframe.getWidth())/2,
(screen.height-jframe.getWidth())/2);
jframe.setLayout(null);
Container contentPane = jframe.getContentPane();
JButton zipBtn;
JButton unzipBtn;
zipBtn = new JButton("壓縮");
unzipBtn = new JButton("解壓");
zipBtn.setSize(60 , 40);
unzipBtn.setSize(60 , 40);
zipBtn.setLocation(40,40);
unzipBtn.setLocation(120 , 40);
contentPane.add(zipBtn);
contentPane.add(unzipBtn);
zipBtn.addActionListener(new ActionHandler());
unzipBtn.addActionListener(new ActionHandler());
jframe.setVisible(true);
}
private JFrame jframe;
private AntZip zip;
private File latestDir;/*記錄最近使用的文件夾路徑*/
/*內部類監聽器*/
class ActionHandler implements ActionListener{
public void actionPerformed(ActionEvent event){
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(latestDir);
String cmd = event.getActionCommand();
if(cmd.equals("壓縮")){
chooser.setFileSelectionMode(
JFileChooser.FILES_AND_DIRECTORIES);
chooser.setMultiSelectionEnabled(true);
int returnVal = chooser.showOpenDialog(jframe);
if(returnVal == JFileChooser.APPROVE_OPTION) {
File[] files = chooser.getSelectedFiles();
if(files!=null){
zip.doZip(files , files[0].getName());
latestDir = files[0].getParentFile();
}
}
}
else if(cmd.equals("解壓")){
chooser.setMultiSelectionEnabled(false) ;
int returnVal = chooser.showOpenDialog(jframe);
if(returnVal == JFileChooser.APPROVE_OPTION) {
File file = chooser.getSelectedFile();
if(file!=null){
zip.unZip(file);
latestDir = file.getParentFile();
}
}
}
}
}
}
AntZip.java:
package myzip;
import java.io.*;
import org.apache.tools.zip.*;
import java.util.Enumeration;
/**
*功能:zip壓縮、解壓(支持中文文件名)
*說明:使用Apache Ant提供的zip工具org.apache.tools.zip實現zip壓縮和解壓功能.
* 解決了由于java.util.zip包不支持漢字的問題。
* 使用java.util.zip包時,當zip文件中有名字為中文的文件時,
* 就會出現異常:
* "Exception in thread "main " java.lang.IllegalArgumentException
* at java.util.zip.ZipInputStream.getUTF8String(ZipInputStream.java:285)
*
*注意:
* 1、使用時把ant.jar放到classpath中,程序中使用import org.apache.tools.zip.*;
* 2、Apache Ant 下載地址:http://ant.apache.org/
* 3、Ant ZIP Online API:
*www.jajakarta.org/ant/ant-1.6.1/docs/mix/manual/api/org/apache/tools/zip/
* 4、本程序使用Ant 1.7.1 中的ant.jar。
* 5、如果只需要Ant的zip壓縮功能,不需要Ant的其它功能,
* 那么可以減小ant.jar的大小。方法是用WinRAR打開ant.jar,
* 把沒有用到的包和class文件都刪除。這樣ant.jar體積就減小了。
* 6、ZipEntry的isDirectory()方法中,目錄以"/"結尾。
*
*僅供編程學習參考.
*
*Copyright (c) Winty
*http://www.tkk7.com/wintys
*
*@author Winty (wintys@gmail.com)
*@version 2008-8-3
*------------------------------------------------
*可將主函數注釋去掉以單獨測試AntZip類。
*Compile:
* javac -cp Ant.jar AntZip.java
*
*Usage:(將ant.jar直接放在當前目錄)
* 壓縮:java -cp Ant.jar;. AntZip -zip [directoryName | fileName]...
* 解壓:java -cp Ant.jar;. AntZip -unzip "fileName.zip"
*
*------------------------------------------------
*2009-3-17:
*修正一處Bug,當解壓的zip文件中根目錄下直接有文件時會出錯。
*將unZip()中的if(!parent.exists())改正為:if(parent!=null && !parent.exists())
*
*2009-3-18:
*多處其它修改
*------------------------------------------------
*/
public class AntZip{
private ZipFile zipFile;
private ZipOutputStream zipOut; //壓縮Zip
private ZipEntry zipEntry;
private static int bufSize; //size of bytes
private byte[] buf;
private int readedBytes;
//用于壓縮中。要去除的絕對父路路徑,目的是將絕對路徑變成相對路徑。
private String deleteAbsoluteParent;
/**
*構造方法。默認緩沖區大小為512字節。
*/
public AntZip(){
this(512);
}
/**
*構造方法。
*@param bufSize 指定壓縮或解壓時的緩沖區大小
*/
public AntZip(int bufSize){
this.bufSize = bufSize;
this.buf = new byte[this.bufSize];
deleteAbsoluteParent = null;
}
/**
*壓縮文件夾內的所有文件和目錄。
*@param zipDirectory 需要壓縮的文件夾名
*/
public void doZip(String zipDirectory){
File zipDir = new File(zipDirectory);
doZip(new File[]{zipDir} , zipDir.getName());
}
/**
*壓縮多個文件或目錄。可以指定多個單獨的文件或目錄。而
*<code>doZip(String zipDirectory)</code>則直接壓縮整個文件夾。
*@param files 要壓縮的文件或目錄組成的<code>File</code>數組。
*@param zipFileName 壓縮后的zip文件名,如果后綴不是".zip",
* 自動添加后綴".zip"。
*/
public void doZip(File[] files , String zipFileName){
//未指定壓縮文件名,默認為"ZipFile"
if(zipFileName==null || zipFileName.equals(""))
zipFileName = "ZipFile";
//添加".zip"后綴
if(!zipFileName.endsWith(".zip"))
zipFileName += ".zip";
try{
this.zipOut = new ZipOutputStream(
new BufferedOutputStream(new FileOutputStream(zipFileName)));
compressFiles(files , this.zipOut , true );
this.zipOut.close();
}catch(IOException ioe){
ioe.printStackTrace();
}
}
/**
*壓縮文件和目錄。由doZip()調用
*@param files 要壓縮的文件
*@param zipOut zip輸出流
*@param isAbsolute 是否是要去除的絕對路徑的根路徑。因為compressFiles()
*會遞歸地被調用,所以只用deleteAbsoluteParent不行。必須用isAbsolute來指明
*compressFiles()是第一次調用,而不是后續的遞歸調用。即如果要壓縮的路徑是
*E:\temp,那么第一次調用時,isAbsolute=true,則deleteAbsoluteParent會記錄
*要刪除的路徑就是E:\ ,當壓縮子目錄E:\temp\folder時,isAbsolute=false,
*再遞歸調用compressFiles()時,deleteAbsoluteParent仍然是E:\ 。從而保證了
*將E:\temp及其子目錄均正確地轉化為相對目錄。這樣壓縮才不會出錯。不然絕對
*路徑E:\也會被寫入到壓縮文件中去。
*/
private void compressFiles(File[] files ,
ZipOutputStream zipOut ,
boolean isAbsolute) throws IOException{
for(File file : files){
if(file==null)continue; //空的文件對象
//刪除絕對父路徑
if(file.isAbsolute()){
if(isAbsolute){
deleteAbsoluteParent = file.getParentFile().getAbsolutePath();
deleteAbsoluteParent = appendSeparator(deleteAbsoluteParent);
}
}
else
deleteAbsoluteParent = "";
if(file.isDirectory()){//是目錄
compressFolder(file , zipOut);
}
else{//是文件
compressFile(file , zipOut);
}
}
}
/**
*壓縮文件或空目錄。由compressFiles()調用。
*@param file 需要壓縮的文件
*@param zipOut zip輸出流
*/
public void compressFile(File file , ZipOutputStream zipOut)
throws IOException{
String fileName = file.toString();
/*去除絕對父路徑。*/
if(file.isAbsolute())
fileName = fileName.substring(deleteAbsoluteParent.length());
if(fileName == null || fileName=="")
return;
/*因為是空目錄,所以要在結尾加一個"/"。
不然就會被當作是空文件。
ZipEntry的isDirectory()方法中,目錄以"/"結尾.
org.apache.tools.zip.ZipEntry :
public boolean isDirectory() {
return getName().endsWith("/");
}
*/
if(file.isDirectory())
fileName = fileName + "/";//此處不能用"\\"
zipOut.putNextEntry(new ZipEntry(fileName));
//如果是文件則需讀;如果是空目錄則無需讀,直接轉到zipOut.closeEntry()。
if(file.isFile()){
FileInputStream fileIn = new FileInputStream(file);
while((this.readedBytes = fileIn.read(this.buf))>0){
zipOut.write(this.buf , 0 , this.readedBytes);
}
fileIn.close();
}
zipOut.closeEntry();
}
/**
*遞歸完成目錄文件讀取。由compressFiles()調用。
*@param dir 需要處理的文件對象
*@param zipOut zip輸出流
*/
private void compressFolder(File dir , ZipOutputStream zipOut)
throws IOException{
File[] files = dir.listFiles();
if(files.length == 0)//如果目錄為空,則單獨壓縮空目錄。
compressFile(dir , zipOut);
else//如果目錄不為空,則分別處理目錄和文件.
compressFiles(files , zipOut , false);
}
/**
*解壓指定zip文件。
*@param unZipFileName 需要解壓的zip文件名
*/
public void unZip(String unZipFileName){
FileOutputStream fileOut;
File file;
InputStream inputStream;
try{
this.zipFile = new ZipFile(unZipFileName);
for(Enumeration entries = this.zipFile.getEntries();
entries.hasMoreElements(); ){
ZipEntry entry = (ZipEntry)entries.nextElement();
file = new File(entry.getName());
if(entry.isDirectory()){//是目錄,則創建之
file.mkdirs();
}
else{//是文件
//如果指定文件的父目錄不存在,則創建之.
File parent = file.getParentFile();
if(parent!=null && !parent.exists()){
parent.mkdirs();
}
inputStream = zipFile.getInputStream(entry);
fileOut = new FileOutputStream(file);
while(( this.readedBytes = inputStream.read(this.buf) ) > 0){
fileOut.write(this.buf , 0 , this.readedBytes );
}
fileOut.close();
inputStream.close();
}
}
this.zipFile.close();
}catch(IOException ioe){
ioe.printStackTrace();
}
}
/**
*給文件路徑或目錄結尾添加File.separator
*@param fileName 需要添加路徑分割符的路徑
*@return 如果路徑已經有分割符,則原樣返回,否則添加分割符后返回。
*/
private String appendSeparator(String path){
if(!path.endsWith(File.separator))
path += File.separator;
return path;
}
/**
*解壓指定zip文件。
*@param unZipFile 需要解壓的zip文件對象
*/
public void unZip(File unZipFile){
unZip(unZipFile.toString());
}
/**
*設置壓縮或解壓時緩沖區大小。
*@param bufSize 緩沖區大小
*/
public void setBufSize(int bufSize){
this.bufSize = bufSize;
}
//主函數,用于測試AntZip類
/*
public static void main(String[] args)throws Exception{
if(args.length>=2){
AntZip zip = new AntZip();
if(args[0].equals("-zip")){
//將后續參數全部轉化為File對象
File[] files = new File[ args.length - 1];
for(int i = 0;i < args.length - 1; i++){
files[i] = new File(args[i + 1]);
}
//將第一個文件名作為zip文件名
zip.doZip(files , files[0].getName());
return ;
}
else if(args[0].equals("-unzip")){
zip.unZip(args[1]);
return ;
}
}
System.out.println("Usage:");
System.out.println("壓縮:java AntZip -zip [directoryName | fileName]... ");
System.out.println("解壓:java AntZip -unzip fileName.zip");
}
*/
}
附件內容:
/MyZip.jar : 打包后的可執行文件,可單獨運行,內含org.apache.tools.zip包。運行環境JRE1.6+
/使用Ant實現zip壓縮解壓功能/ant.jar : 精簡后的ant包,只包含org.apache.tools.zip
/使用Ant實現zip壓縮解壓功能/AntZip.java
/使用Ant實現zip壓縮解壓功能/MyZip.java
[附件]:
使用Ant實現zip壓縮解壓功能.zip
posted on 2009-03-19 13:17
天堂露珠 閱讀(4765)
評論(11) 編輯 收藏 所屬分類:
Java