java · 2023-03-31 0

使用 ZipFile 操作 ZIP

准备

有压缩文件:

zxm@zxm-pc:~$ unzip -t test.zip 
Archive:  test.zip
    testing: a.txt                    OK
    testing: b.txt                    OK
    testing: c/                       OK
    testing: c/c.txt                  OK
    testing: d.zip                    OK
No errors detected in compressed data of test.zip.

一、解压 zip

可使用 ZipFile 或 ZipInputStream 解压 zip 文件

@Test
public void testUnzip1() throws Exception {
    String targetRoot = "/home/zxm/test";

    ZipFile zipFile = new ZipFile(new File("/home/zxm/test.zip"));
    System.out.println("file count:" + zipFile.size());

    Enumeration enumeration = zipFile.entries();
    while (enumeration.hasMoreElements()) {
        ZipEntry entry = (ZipEntry) enumeration.nextElement();
        String name = entry.getName();
        System.out.println("name:" + name);

        File outFile = new File(targetRoot + "/" + name);
        if (entry.isDirectory()) {
            // 如果是目录,则创建目录
            if (!outFile.exists()) {
                outFile.mkdirs();
            }
            continue;
        }

        BufferedInputStream inputStream = new BufferedInputStream(zipFile.getInputStream(entry));
        BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(outFile));
        int len;
        byte[] buffer = new byte[1024];
        while ((len = inputStream.read(buffer)) > 0) {
            outputStream.write(buffer, 0, len);
        }
        outputStream.close();
        inputStream.close();
    }
    zipFile.close();
}

@Test
public void testUnzip2() throws Exception {
    String targetRoot = "/home/zxm/test";
    ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream("/home/zxm/test.zip"));

    ZipEntry zipEntry = null;
    while ((zipEntry = zipInputStream.getNextEntry()) != null) {
        String name = zipEntry.getName();
        System.out.println("name:" + name);

        File outFile = new File(targetRoot + "/" + name);
        if (name.endsWith("/")) {
            // 如果是目录,则创建目录
            if (!outFile.exists()) {
                outFile.mkdir();
            }
            continue;
        }

        BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(outFile));
        int len;
        byte[] buffer = new byte[1024];
        while ((len = zipInputStream.read(buffer, 0, buffer.length)) > 0) {
            outputStream.write(buffer, 0, len);
        }
        outputStream.close();

    }
    zipInputStream.close();
}

二、读取 zip

可使用 ZipFile 或 ZipInputStream 读取 zip。若读取嵌套的 zip,可把嵌套的 zip 写入临时文件,再从嵌套的 zip 读取内部文件内容

@Test
public void testReadZip1() throws Exception {
    ZipFile zipFile = new ZipFile(new File("/home/zxm/test.zip"));
    System.out.println("file count:" + zipFile.size());

    Enumeration enumeration = zipFile.entries();
    while (enumeration.hasMoreElements()) {
        ZipEntry entry = (ZipEntry) enumeration.nextElement();
        String name = entry.getName();
        System.out.println("name:" + name);

        if (name.endsWith(".zip")) {
            continue;
        }

        BufferedReader br = new BufferedReader(new InputStreamReader(zipFile.getInputStream(entry)));
        String line;
        StringBuilder builder = new StringBuilder();
        while ((line = br.readLine()) != null) {
            builder.append(line);
        }
        System.out.println("content: " + builder);
    }
    zipFile.close();
}

@Test
public void testReadZip2() throws Exception {
    ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream("/home/zxm/test.zip"));

    ZipEntry zipEntry = null;
    while ((zipEntry = zipInputStream.getNextEntry()) != null) {
        String name = zipEntry.getName();
        System.out.println("name:" + name);

        if (name.endsWith(".zip")) {
            continue;
        }

        BufferedReader br = new BufferedReader(new InputStreamReader(zipInputStream));
        String line;
        StringBuilder builder = new StringBuilder();
        while ((line = br.readLine()) != null) {
            builder.append(line);
        }
        System.out.println("content: " + builder);
    }
    zipInputStream.closeEntry();
}

读取指定的单个文件。若读取嵌套的 zip 中的单个文件,先把嵌套的 zip 中写入临时文件,再从临时的 zip 文件,读取指定的单个文件

@Test
public void testReadZipOneFile() throws Exception {
    ZipFile zipFile = new ZipFile(new File("/home/zxm/test.zip"));
    InputStream inputStream = zipFile.getInputStream(zipFile.getEntry("c/c.txt"));

    BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
    String line;
    StringBuilder builder = new StringBuilder();
    while ((line = br.readLine()) != null) {
        builder.append(line);
    }
    System.out.println("content: " + builder);
}

@Test
public void testReadInnerZipOneFile() throws Exception {
    String outerZipFilePath = "/home/zxm/test.zip";
    String innerZipFileName = "d.zip";
    String targetFileName = "d.txt";

    ZipFile outerZipFile = new ZipFile(outerZipFilePath);
    ZipEntry innerZipEntry = outerZipFile.getEntry(innerZipFileName);

    // 创建临时文件
    File tempFile = File.createTempFile("inner_zip_", ".zip");
    FileOutputStream tempOs = new FileOutputStream(tempFile);
    InputStream tempIs = outerZipFile.getInputStream(innerZipEntry);
    byte[] buffer = new byte[1024];
    int len;
    while ((len = tempIs.read(buffer)) > 0) {
        tempOs.write(buffer, 0, len);
    }
    tempOs.close();
    tempIs.close();

    // 读取内部zip的一个文件内容
    ZipFile innerZipFile = new ZipFile(tempFile);
    InputStream inputStream = innerZipFile.getInputStream(innerZipFile.getEntry(targetFileName));

    BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
    String line;
    StringBuilder builder = new StringBuilder();
    while ((line = br.readLine()) != null) {
        builder.append(line);
    }
    System.out.println("content: " + builder);
}

三、压缩 zip

把多个文件,打包进 zip

@Test
public void testZip() throws Exception {
    Map<String, File> map = new HashMap<>();
    map.put("a.txt", new File("/home/zxm/test/a.txt"));
    map.put("b.txt", new File("/home/zxm/test/b.txt"));
    map.put("c/c.txt", new File("/home/zxm/test/c/c.txt"));

    ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream("/home/zxm/test1.zip"));
    for (Map.Entry<String, File> entry : map.entrySet()) {
        String name = entry.getKey();
        File file = entry.getValue();

        ZipEntry zipEntry = new ZipEntry(name);
        zipOutputStream.putNextEntry(zipEntry);

        BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(file));
        int len;
        byte[] buffer = new byte[1024];
        while ((len = inputStream.read(buffer)) > 0) {
            zipOutputStream.write(buffer, 0, len);
        }
        inputStream.close();
    }

    zipOutputStream.closeEntry();
    zipOutputStream.close();
}