Zipping dan Unzipping di Java

1. Ikhtisar

Dalam tutorial singkat ini, kita akan membahas cara meng-zip file ke dalam arsip dan cara mengekstrak arsip - semuanya menggunakan pustaka inti yang disediakan oleh Java.

Pustaka inti ini adalah bagian dari paket java.util.zip - di mana kita dapat menemukan semua utilitas terkait zipping dan unzip.

2. Zip File

Pertama-tama mari kita lihat operasi sederhana - membuat zip satu file.

Untuk contoh kami di sini, kami akan membuat zip file bernama test1.txt menjadi arsip bernama compressed.zip .

Kami tentu saja pertama-tama akan mengakses file dari disk - mari kita lihat:

public class ZipFile { public static void main(String[] args) throws IOException { String sourceFile = "test1.txt"; FileOutputStream fos = new FileOutputStream("compressed.zip"); ZipOutputStream zipOut = new ZipOutputStream(fos); File fileToZip = new File(sourceFile); FileInputStream fis = new FileInputStream(fileToZip); ZipEntry zipEntry = new ZipEntry(fileToZip.getName()); zipOut.putNextEntry(zipEntry); byte[] bytes = new byte[1024]; int length; while((length = fis.read(bytes)) >= 0) { zipOut.write(bytes, 0, length); } zipOut.close(); fis.close(); fos.close(); } }

3. Zip Beberapa File

Selanjutnya, mari kita lihat cara membuat zip beberapa file menjadi satu file zip. Kami akan mengompres test1.txt dan test2.txt menjadi multiCompressed.zip :

public class ZipMultipleFiles { public static void main(String[] args) throws IOException { List srcFiles = Arrays.asList("test1.txt", "test2.txt"); FileOutputStream fos = new FileOutputStream("multiCompressed.zip"); ZipOutputStream zipOut = new ZipOutputStream(fos); for (String srcFile : srcFiles) { File fileToZip = new File(srcFile); FileInputStream fis = new FileInputStream(fileToZip); ZipEntry zipEntry = new ZipEntry(fileToZip.getName()); zipOut.putNextEntry(zipEntry); byte[] bytes = new byte[1024]; int length; while((length = fis.read(bytes)) >= 0) { zipOut.write(bytes, 0, length); } fis.close(); } zipOut.close(); fos.close(); } }

4. Zip Direktori

Sekarang, mari kita bahas cara membuat zip seluruh direktori. Kami akan mengarahkan zipTest ke dirCompressed.zip :

public class ZipDirectory { public static void main(String[] args) throws IOException { String sourceFile = "zipTest"; FileOutputStream fos = new FileOutputStream("dirCompressed.zip"); ZipOutputStream zipOut = new ZipOutputStream(fos); File fileToZip = new File(sourceFile); zipFile(fileToZip, fileToZip.getName(), zipOut); zipOut.close(); fos.close(); } private static void zipFile(File fileToZip, String fileName, ZipOutputStream zipOut) throws IOException { if (fileToZip.isHidden()) { return; } if (fileToZip.isDirectory()) { if (fileName.endsWith("/")) { zipOut.putNextEntry(new ZipEntry(fileName)); zipOut.closeEntry(); } else { zipOut.putNextEntry(new ZipEntry(fileName + "/")); zipOut.closeEntry(); } File[] children = fileToZip.listFiles(); for (File childFile : children) { zipFile(childFile, fileName + "/" + childFile.getName(), zipOut); } return; } FileInputStream fis = new FileInputStream(fileToZip); ZipEntry zipEntry = new ZipEntry(fileName); zipOut.putNextEntry(zipEntry); byte[] bytes = new byte[1024]; int length; while ((length = fis.read(bytes)) >= 0) { zipOut.write(bytes, 0, length); } fis.close(); } }

Perhatikan bahwa:

  • Untuk membuat zip sub-direktori, kami mengulanginya secara rekursif.
  • Setiap kali kami menemukan direktori, kami menambahkan namanya ke nama keturunan ZipEntry untuk menyimpan hierarki.
  • Kami juga membuat entri direktori untuk setiap direktori kosong

5. Buka zip Arsip

Sekarang mari kita unzip arsip dan mengekstrak isinya.

Untuk contoh ini, kami akan mengekstrak compressed.zip ke folder baru bernama unzipTest .

Mari kita lihat:

public class UnzipFile { public static void main(String[] args) throws IOException { String fileZip = "src/main/resources/unzipTest/compressed.zip"; File destDir = new File("src/main/resources/unzipTest"); byte[] buffer = new byte[1024]; ZipInputStream zis = new ZipInputStream(new FileInputStream(fileZip)); ZipEntry zipEntry = zis.getNextEntry(); while (zipEntry != null) { // ... } zis.closeEntry(); zis.close(); } }

Di dalam while loop, kita akan mengulang setiap ZipEntry dan pertama-tama memeriksa apakah itu direktori . Jika ya, maka kita akan membuat direktori menggunakan metode mkdirs () ; jika tidak, kami akan melanjutkan dengan membuat file:

while (zipEntry != null) { File newFile = newFile(destDir, zipEntry); if (zipEntry.isDirectory()) { if (!newFile.isDirectory() && !newFile.mkdirs()) { throw new IOException("Failed to create directory " + newFile); } } else { // fix for Windows-created archives File parent = newFile.getParentFile(); if (!parent.isDirectory() && !parent.mkdirs()) { throw new IOException("Failed to create directory " + parent); } // write file content FileOutputStream fos = new FileOutputStream(newFile); int len; while ((len = zis.read(buffer)) > 0) { fos.write(buffer, 0, len); } fos.close(); } zipEntry = zis.getNextEntry(); }

Satu catatan di sini adalah bahwa di cabang lain , kami juga memeriksa terlebih dahulu apakah direktori induk file tersebut ada. Ini diperlukan untuk arsip yang dibuat di Windows, di mana direktori root tidak memiliki entri yang sesuai di file zip.

Poin penting lainnya dapat dilihat di metode newFile () :

public static File newFile(File destinationDir, ZipEntry zipEntry) throws IOException { File destFile = new File(destinationDir, zipEntry.getName()); String destDirPath = destinationDir.getCanonicalPath(); String destFilePath = destFile.getCanonicalPath(); if (!destFilePath.startsWith(destDirPath + File.separator)) { throw new IOException("Entry is outside of the target dir: " + zipEntry.getName()); } return destFile; }

Metode ini mencegah penulisan file ke sistem file di luar folder target. Kerentanan ini disebut Zip Slip dan Anda dapat membaca lebih lanjut di sini.

6. Kesimpulan

Tutorial ini mengilustrasikan bagaimana kita dapat menggunakan pustaka Java untuk operasi zip dan unzip file.

Penerapan contoh-contoh ini dapat ditemukan di GitHub.