Hôm nay chúng ta sẽ tìm hiểu về cách nén file Java. Chúng ta cũng sẽ thử nén một thư mục và tạo file ZIP bằng chương trình Java.
File ZIP trong Java
java.util.zip.ZipOutputStream
có thể được sử dụng để nén một file sang định dạng ZIP.
Vì một file ZIP có thể chứa nhiều mục (entries), nên ZipOutputStream sử dụng java.util.zip.ZipEntry
để biểu diễn từng mục trong file ZIP.
Việc tạo một tệp zip cho một tệp duy nhất rất dễ dàng, chúng ta cần tạo một đối tượng ZipOutputStream từ đối tượng FileOutputStream của tệp đích. Sau đó, chúng ta thêm một ZipEntry mới vào ZipOutputStream và sử dụng FileInputStream để đọc tệp nguồn vào đối tượng ZipOutputStream. Sau khi ghi xong, chúng ta cần đóng ZipEntry và giải phóng tất cả tài nguyên.
Java Zip Folder
Nén một thư mục thì hơi phức tạp hơn một chút. Đầu tiên, chúng ta cần lấy danh sách các file với đường dẫn tuyệt đối. Sau đó, xử lý từng file một cách riêng biệt. Với mỗi file, chúng ta phải thêm một ZipEntry và sử dụng FileInputStream để đọc nội dung file nguồn rồi ghi vào ZipEntry tương ứng của file đó.
Ví dụ Java Zip
Dưới đây là chương trình Java minh họa cách nén một file đơn lẻ hoặc nén cả một thư mục trong Java.
package com.journaldev.files;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZipFiles {
List<String> filesListInDir = new ArrayList<String>();
public static void main(String[] args) {
File file = new File("/Users/pankaj/sitemap.xml");
String zipFileName = "/Users/pankaj/sitemap.zip";
File dir = new File("/Users/pankaj/tmp");
String zipDirName = "/Users/pankaj/tmp.zip";
zipSingleFile(file, zipFileName);
ZipFiles zipFiles = new ZipFiles();
zipFiles.zipDirectory(dir, zipDirName);
}
/**
* This method zips the directory
* @param dir
* @param zipDirName
*/
private void zipDirectory(File dir, String zipDirName) {
try {
populateFilesList(dir);
//now zip files one by one
//create ZipOutputStream to write to the zip file
FileOutputStream fos = new FileOutputStream(zipDirName);
ZipOutputStream zos = new ZipOutputStream(fos);
for(String filePath : filesListInDir){
System.out.println("Zipping "+filePath);
//for ZipEntry we need to keep only relative file path, so we used substring on absolute path
ZipEntry ze = new ZipEntry(filePath.substring(dir.getAbsolutePath().length()+1, filePath.length()));
zos.putNextEntry(ze);
//read the file and write to ZipOutputStream
FileInputStream fis = new FileInputStream(filePath);
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) > 0) {
zos.write(buffer, 0, len);
}
zos.closeEntry();
fis.close();
}
zos.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* This method populates all the files in a directory to a List
* @param dir
* @throws IOException
*/
private void populateFilesList(File dir) throws IOException {
File[] files = dir.listFiles();
for(File file : files){
if(file.isFile()) filesListInDir.add(file.getAbsolutePath());
else populateFilesList(file);
}
}
/**
* This method compresses the single file to zip format
* @param file
* @param zipFileName
*/
private static void zipSingleFile(File file, String zipFileName) {
try {
//create ZipOutputStream to write to the zip file
FileOutputStream fos = new FileOutputStream(zipFileName);
ZipOutputStream zos = new ZipOutputStream(fos);
//add a new Zip Entry to the ZipOutputStream
ZipEntry ze = new ZipEntry(file.getName());
zos.putNextEntry(ze);
//read the file and write to ZipOutputStream
FileInputStream fis = new FileInputStream(file);
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) > 0) {
zos.write(buffer, 0, len);
}
//Close the zip entry to write to zip file
zos.closeEntry();
//Close resources
zos.close();
fis.close();
fos.close();
System.out.println(file.getCanonicalPath()+" is zipped to "+zipFileName);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Đầu ra của chương trình ví dụ java zip ở trên là:
/Users/pankaj/sitemap.xml is zipped to /Users/pankaj/sitemap.zip
Zipping /Users/pankaj/tmp/.DS_Store
Zipping /Users/pankaj/tmp/data/data.dat
Zipping /Users/pankaj/tmp/data/data.xml
Zipping /Users/pankaj/tmp/data/xmls/project.xml
Zipping /Users/pankaj/tmp/data/xmls/web.xml
Zipping /Users/pankaj/tmp/data.Xml
Zipping /Users/pankaj/tmp/DB.xml
Zipping /Users/pankaj/tmp/item.XML
Zipping /Users/pankaj/tmp/item.xsd
Zipping /Users/pankaj/tmp/ms/data.txt
Zipping /Users/pankaj/tmp/ms/project.doc
Lưu ý rằng khi ghi log các file vào tệp zip trong thư mục, mình đang in ra đường dẫn tuyệt đối. Tuy nhiên, khi thêm ZipEntry, mình lại sử dụng đường dẫn tương đối tính từ thư mục gốc. Điều này giúp khi giải nén (unzip), chương trình sẽ tái tạo lại đúng cấu trúc thư mục ban đầu. Và đó là toàn bộ ví dụ về nén file trong Java.