隨筆 - 117  文章 - 72  trackbacks - 0

          聲明:原創作品(標有[原]字樣)轉載時請注明出處,謝謝。

          常用鏈接

          常用設置
          常用軟件
          常用命令
           

          訂閱

          訂閱

          留言簿(7)

          隨筆分類(130)

          隨筆檔案(123)

          搜索

          •  

          積分與排名

          • 積分 - 155773
          • 排名 - 390

          最新評論

          [關鍵詞]: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.aygfsteel.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 天堂露珠 閱讀(4767) 評論(11)  編輯  收藏 所屬分類: Java

          FeedBack:
          # re: [原]使用Ant實現zip壓縮解壓功能 2009-06-11 16:23 豬影橫飛
          你好,學習了你的ANT實現ZIP壓縮技術,受益匪淺,想問下,如果我想做成壓縮雙機文件通信(即采用服務端/客戶端形式),點擊發送端按鈕->選擇文件->壓縮成*.zip文件->發送給客戶端,點擊接收端按鈕->選擇保存路徑->接收*.zip文件->解壓*.zip文件,請問如何實現和調用?
          hszcy521@163.com  回復  更多評論
            
          # re: [原]使用Ant實現zip壓縮解壓功能 2009-06-11 20:17 天堂露珠
          那就需要用到TCP或UDP通信了,參見我的CSDN文章:《Java UDP網絡編程 - 最簡單示例》:http://blog.csdn.net/wintys/archive/2008/12/15/3525643.aspx ,以及《Java TCP網絡編程 - 最簡單示例》:http://blog.csdn.net/wintys/archive/2008/12/15/3525619.aspx 。  回復  更多評論
            
          # re: [原]使用Ant實現zip壓縮解壓功能 2009-06-11 21:56 豬影橫飛
          恩,這個我會寫已經寫好了SERVER.JAVA和CLIENT.JAVA了,但里邊都帶有main函數,在JDK編程的環境下能直接運行,我想問的就是如何再GUI.JAVA里的事件處理中按我的流程調用?服務端先壓縮再傳送,客戶端先接收再解壓  回復  更多評論
            
          # re: [原]使用Ant實現zip壓縮解壓功能 2009-06-11 23:16 天堂露珠
          @豬影橫飛
          兩個客戶端都一直在監聽著指定的端口,用線程實現監聽。
          以下僅為示意性代碼:

          1、發送
          比如就用我寫的MyZip.java的界面,把"壓縮"改成"發送",
          if(cmd.equals("壓縮")){
          ......
          if(files!=null){
          //先壓縮所選文件夾內的文件,結果會生成一個zip文件,假設為"file.zip"
          zip.doZip(files , files[0].getName());
          latestDir = files[0].getParentFile();

          //udp為UDP通信類。
          //獲取"file.zip"的字節數組,啟動一個線程,
          //把它當作一個或多個數據包發送出去,
          //而此時,另一個客戶端正在監聽著,它收到數據后,進行相反的操作。
          udp.send(filePacket);
          }
          ......
          }


          2、接收
          也就是說,沒有數據發送的時候,兩個客戶端都有一個后臺線程運行著:
          class Client implements Runnable{
          public void run(){
          while(true){
          //接收,沒有收到時,將一直等待
          datagramSocket.receive(recvPacket);
          //解壓
          Unzip();
          }
          }
          }  回復  更多評論
            
          # re: [原]使用Ant實現zip壓縮解壓功能 2009-06-12 22:36 豬影橫飛
          @天堂露珠
          謝謝你的指點,非常感謝!~  回復  更多評論
            
          # re: [原]使用Ant實現zip壓縮解壓功能 2009-06-13 21:07 王琦均
          如果是要求以流的形式傳入zip文件,那怎么解決呢
          我看了ant里面好像沒有提供這樣的方法。
          里面 沒有zipInputStream 只有zipOutputStream

          我這里提的方法就是:
          //這里的流就是出入的zip文件流
          public int getText(InputStream is){

          }  回復  更多評論
            
          # re: [原]使用Ant實現zip壓縮解壓功能 2009-06-13 22:34 天堂露珠
          @王琦均
          只有自己獨立解決問題,才可能真正成長,不能每一步都問吧。
          其實我的程序中已經用到了,org.apache.tools.zip.ZipFile.getInputStream(ZipEntry ze)就是輸入流。  回復  更多評論
            
          # re: [原]使用Ant實現zip壓縮解壓功能 2009-06-14 01:20 王琦均
          @天堂露珠
          外部只調我這個程序的這個方法哦
          也就是外部程序只給我傳個流進來。  回復  更多評論
            
          # re: [原]使用Ant實現zip壓縮解壓功能 2009-06-14 01:23 王琦均
          @天堂露珠
          外部是不會用org.apache.tools.zip.ZipFile.getInputStream(ZipEntry ze)
          來給你轉化的。
          直接就是個文件流傳進來的!  回復  更多評論
            
          # re: [原]使用Ant實現zip壓縮解壓功能 2009-06-29 15:41 shappy
          @王琦均 可能我的答案是你想要的,你是希望直接輸出zip流,而不是zip文件嗎
          //創建zip流
          ByteArrayOutputStream out = new ByteArrayOutputStream();
          ZipOutputStream zout = new ZipOutputStream(out);
          //省略
          ByteArrayInputStream zin= new ByteArrayInputStream(out.toByteArray());
          byte[] aryRead = new byte[zin.available()];
          //有inputstream,也有byte[]

            回復  更多評論
            
          # re: [原]使用Ant實現zip壓縮解壓功能 2009-06-29 15:51 shappy
          //創建zip流
          ByteArrayOutputStream out = new ByteArrayOutputStream();
          ZipOutputStream zout = new ZipOutputStream(out);
          //省略壓縮代碼
          zout.close(); //很奇怪,這里如果不關閉的話,檢測到輸出的流稍小一點,而且數據也有一些差異,誰能解釋一下
          ByteArrayInputStream zin= new ByteArrayInputStream(out.toByteArray());
          byte[] aryRead = new byte[zin.available()];
          //有inputstream,也有byte[]   回復  更多評論
            
          主站蜘蛛池模板: 五莲县| 上思县| 中超| 娄烦县| 雅安市| 云阳县| 保定市| 扎赉特旗| 佛山市| 卢氏县| 肥东县| 江源县| 普洱| 邹城市| 望奎县| 永清县| 金阳县| 灌南县| 西昌市| 塔河县| 东阿县| 沈阳市| 福州市| 年辖:市辖区| 桦川县| 日喀则市| 天津市| 广州市| 云浮市| 红河县| 五指山市| 都匀市| 乐至县| 余庆县| 泗水县| 北宁市| 南华县| 苍山县| 大同市| 广安市| 鄄城县|