Hướng dẫn nén và giải nén trong Java
Công ty Vĩnh Cửu tuyển dụng lập trình viên Java

1- Giới thiệu

History:
  • Create document: 20-09-2014

2- Đọc ghi file zip sử dụng java.util.zip

Để sử lý các công việc liên quan tới nén và giải nén, JDK cung cấp cho bạn package java.util.zip với một số class để làm việc này.

Đáng tiếc là thư viện này không thể đọc và giải nén các định dạng phổ biến khác như rar, hoặc 7zip. Để giải sử lý các định dạng rar, 7zip, .. bạn cần có một thư viện khác. Trong tài liệu này tôi có để cập tới các thư viện để làm việc này.
Đây là hình ảnh một file zip được mở bằng công cụ Winrar.
java.util.zip coi các file trong file zip là các ZipEntry.
  • ListZipEntriesDemo.java
package org.o7planning.tutorial.javaiozip;

import java.io.FileInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class ListZipEntriesDemo {

 public static void main(String[] args) {
     String FILE_PATH = "C:/test/datas.zip";

     ZipInputStream zipIs = null;
     try {
         // Khởi tạo ZipInputStream.
         zipIs = new ZipInputStream(new FileInputStream(FILE_PATH));

         ZipEntry entry = null;
         // Duyệt từng Entry (Từ trên xuống dưới cho tới hết)

         while ((entry = zipIs.getNextEntry()) != null) {
             if (entry.isDirectory()) {
                 System.out.print("Directory: ");
             } else {
                 System.out.print("File: ");
             }
             System.out.println(entry.getName());
         }

     } catch (Exception e) {
         e.printStackTrace();
     } finally {
         try {
             zipIs.close();
         } catch (Exception e) {
         }
     }
 }

}
Kết quả chạy ví dụ:
Ví dụ giải nén file zip vào một thư mục nào đó:
  • UnZipDemo.java
package org.o7planning.tutorial.javaiozip;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class UnZipDemo {

   public static void main(String[] args) {
       final String OUTPUT_FOLDER = "C:/output";
       String FILE_PATH = "C:/test/datas.zip";

       // Tạo thư mục Output nếu nó chưa có
       File folder = new File(OUTPUT_FOLDER);
       if (!folder.exists()) {
           folder.mkdirs();
       }
       // Bộ đệm.
       byte[] buffer = new byte[1024];

       ZipInputStream zipIs = null;
       try {
           // Khởi tạo ZipInputStream.
           zipIs = new ZipInputStream(new FileInputStream(FILE_PATH));

           ZipEntry entry = null;
           // Duyệt từng Entry (Từ trên xuống dưới cho tới hết)
           while ((entry = zipIs.getNextEntry()) != null) {
               String entryName = entry.getName();
               String outFileName = OUTPUT_FOLDER + File.separator + entryName;
               System.out.println("Unzip: " + outFileName);

               if (entry.isDirectory()) {
                   // Tạo thư mục.
                   new File(outFileName).mkdirs();
               } else {
                   // Tạo luồng ghi ra file.
                   FileOutputStream fos = new FileOutputStream(outFileName);

                   int len;
                   // Đọc dữ liệu trên Entry hiện tại.
                   while ((len = zipIs.read(buffer)) > 0) {
                       fos.write(buffer, 0, len);
                   }

                   fos.close();
               }

           }
       } catch (Exception e) {
           e.printStackTrace();
       } finally {
           try {
               zipIs.close();
           } catch (Exception e) {
           }
       }
   }

}
Kết quả chạy ví dụ:

Nén thư mục

  • ZipDirectory.java
package org.o7planning.tutorial.javaiozip;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class ZipDirectory {

   public ZipDirectory() {

   }

   /**
    * Method nén một thư mục.
    */
   public void zipDirectory(File inputDir, File outputZipFile) {
       // Tạo thư mục cha cho file output.
       // Create parent directory for output file
       outputZipFile.getParentFile().mkdirs();

       String inputDirPath = inputDir.getAbsolutePath();
       byte[] buffer = new byte[1024];

       FileOutputStream fileOs = null;
       ZipOutputStream zipOs = null;
       try {
           // Tất cả các file con cháu,.. trong inputDir.
           List<File> allFiles = this.listChildFiles(inputDir);
           // Bây giờ thì zip lần lượt từng file.
           // Tạo ZipOutputStream để ghi file zip.
           fileOs = new FileOutputStream(outputZipFile);
           //
           zipOs = new ZipOutputStream(fileOs);
           for (File file : allFiles) {
               String filePath = file.getAbsolutePath();

               System.out.println("Zipping " + filePath);
               // entryName chính là đường dẫn tương đối.
               String entryName = filePath
                       .substring(inputDirPath.length() + 1);

               ZipEntry ze = new ZipEntry(entryName);
               // Thêm entry vào file zip.
               zipOs.putNextEntry(ze);
               // Đọc dữ liệu file cần zip và ghi vào luồng zip
               FileInputStream fileIs = new FileInputStream(filePath);

               int len;
               while ((len = fileIs.read(buffer)) > 0) {
                   zipOs.write(buffer, 0, len);
               }
               fileIs.close();
           }
       } catch (IOException e) {
           e.printStackTrace();
       } finally {
           closeQuite(zipOs);
           closeQuite(fileOs);
       }

   }

   private void closeQuite(OutputStream out) {
       try {
           out.close();
       } catch (Exception e) {
       }
   }

   /**
    * Method này trả về danh sách các file, bao gồm cả cháu chắt của thư mục
    * đầu vào.
    */
   private List<File> listChildFiles(File dir) throws IOException {
       List<File> allFiles = new ArrayList<File>();

       // Danh sách các file con trực tiếp của thư mục.
       File[] childFiles = dir.listFiles();
       for (File file : childFiles) {
           if (file.isFile()) {
               allFiles.add(file);
           } else {
               // Gọi đệ quy.
               List<File> files = this.listChildFiles(file);
               allFiles.addAll(files);
           }
       }
       return allFiles;
   }

   public static void main(String[] args) {
       ZipDirectory zipDir = new ZipDirectory();

       File inputDir = new File("C:/datas");
       File outputZipFile = new File("C:/output/datas.zip");

       zipDir.zipDirectory(inputDir, outputZipFile);

   }
}
Kết quả chạy ví dụ:

3- Đọc ghi file jar sử dụng java.util.jar

Về cơ bản việc đọc ghi file jar không có gì khác biệt so với file Zip.
  • JarInputStream mở rộng từ ZipInputStream hỗ trợ thêm tính năng đọc các thông tin MANIFEST.
  • JarOutputStream mở rộng từ ZipOutputStream hỗ trợ thêm tính năng ghi thông tin MANIFEST.
Các file thư viện jar thông thường của java thường có thông tin MANIFEST rất đơn giản.
Ví dụ đây là một file MANIFEST.MF đóng gói trong file jar của 1 ứng dụng RAP có nhiều thông tin hơn:
 
  • META-INF/MANIFEST.MF
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: RAPWorkbenchTutorial
Bundle-SymbolicName: RAPWorkbenchTutorial;singleton:=true
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: rapworkbenchtutorial.Activator
Require-Bundle: org.eclipse.rap.ui;bundle-version="2.3.0",
org.apache.felix.gogo.command;bundle-version="0.10.0",
org.apache.felix.gogo.runtime;bundle-version="0.10.0",
org.apache.felix.gogo.shell;bundle-version="0.10.0",
org.eclipse.equinox.console;bundle-version="1.1.0",
org.eclipse.equinox.http.jetty;bundle-version="3.0.200",
org.eclipse.equinox.ds;bundle-version="1.4.200",
org.eclipse.rap.rwt.osgi;bundle-version="2.3.0",
org.eclipse.rap.design.example;bundle-version="2.3.0"
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-ActivationPolicy: lazy
Ví dụ một file jar mở với Winrar:
Các thực thể trong file jar được coi là các JarEntry.
Một ví dụ đơn giản đọc thông tin MANIFEST của file jar. Dưới đây là hình ảnh nội dung của một file Manifest đơn giản.
  • ReadJarFileDemo.java
package org.o7planning.tutorial.jar;

import java.io.FileInputStream;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;

public class ReadJarFileDemo {

   public static void main(String[] args) {
       String FILE_PATH = "C:/DevPrograms/Java/jdk1.7.0_45/lib/dt.jar";

       JarInputStream zipIs = null;
       try {
           // Khởi tạo JarInputStream.
           zipIs = new JarInputStream(new FileInputStream(FILE_PATH));

           // Đọc thông tin Manifest:
           Manifest manifest = zipIs.getManifest();
           Attributes atts = manifest.getMainAttributes();
           String version = atts.getValue("Manifest-Version");
           String createdBy = atts.getValue("Created-By");
           System.out.println("Manifest-Version:" + version);
           System.out.println("Created-By:" + createdBy);
           System.out.println("========================");
           
           JarEntry entry = null;
           // Duyệt từng Entry (Từ trên xuống dưới cho tới hết)
           while ((entry = zipIs.getNextJarEntry()) != null) {
               if (entry.isDirectory()) {
                   System.out.print("Folder: ");
               } else {
                   System.out.print("File: ");
               }
               System.out.println(entry.getName());
           }

       } catch (Exception e) {
           e.printStackTrace();
       } finally {
           try {
               zipIs.close();
           } catch (Exception e) {
           }
       }
   }

}
Kết quả chạy ví dụ:

4- Sử lý file RAR

Để sử lý file RAR bạn cần một thư viện mã nguồn mở. Bạn có thể sử dụng một trong các thư viện sau, được đánh giá tốt theo thứ tự giảm dần.
Trong tài liệu này tôi sẽ hướng dẫn bạn sử dụng  JUnRar  (Phiên bản tại thời điểm 9-2014 đang  là 0.7)
Download junrar:
  • TODO...