Java操作ZIP案例

wen java案例 3

本文目录导读:

Java操作ZIP案例

  1. 基础ZIP压缩和解压
  2. 使用Apache Commons Compress库
  3. 加密ZIP文件
  4. 实用工具类

我将为您提供几个Java操作ZIP文件的完整案例,涵盖压缩、解压、加密等常见场景。

基础ZIP压缩和解压

1 压缩文件/文件夹为ZIP

import java.io.*;
import java.nio.file.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZipCompressor {
    /**
     * 压缩文件或文件夹
     * @param sourcePath 源文件/文件夹路径
     * @param zipPath 目标ZIP文件路径
     */
    public static void compress(String sourcePath, String zipPath) throws IOException {
        File sourceFile = new File(sourcePath);
        try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipPath))) {
            compressFile(sourceFile, sourceFile.getName(), zos);
        }
    }
    private static void compressFile(File file, String fileName, ZipOutputStream zos) 
            throws IOException {
        if (file.isDirectory()) {
            // 创建目录条目
            if (!fileName.endsWith("/")) {
                fileName += "/";
            }
            zos.putNextEntry(new ZipEntry(fileName));
            zos.closeEntry();
            // 递归处理子文件和子目录
            File[] files = file.listFiles();
            if (files != null) {
                for (File childFile : files) {
                    compressFile(childFile, fileName + childFile.getName(), zos);
                }
            }
        } else {
            // 创建文件条目
            zos.putNextEntry(new ZipEntry(fileName));
            try (FileInputStream fis = new FileInputStream(file)) {
                byte[] buffer = new byte[1024];
                int len;
                while ((len = fis.read(buffer)) > 0) {
                    zos.write(buffer, 0, len);
                }
            }
            zos.closeEntry();
        }
    }
    public static void main(String[] args) {
        try {
            compress("D:/test/folder", "D:/test/output.zip");
            System.out.println("压缩完成!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2 解压ZIP文件

import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class ZipExtractor {
    /**
     * 解压ZIP文件
     * @param zipPath ZIP文件路径
     * @param destDir 目标目录
     */
    public static void extract(String zipPath, String destDir) throws IOException {
        File destFile = new File(destDir);
        if (!destFile.exists()) {
            destFile.mkdirs();
        }
        try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipPath))) {
            ZipEntry entry;
            byte[] buffer = new byte[1024];
            while ((entry = zis.getNextEntry()) != null) {
                String entryName = entry.getName();
                File newFile = new File(destDir + File.separator + entryName);
                // 防止路径穿越
                String canonicalPath = newFile.getCanonicalPath();
                if (!canonicalPath.startsWith(destFile.getCanonicalPath())) {
                    throw new IOException("非法路径: " + entryName);
                }
                if (entry.isDirectory()) {
                    // 创建目录
                    newFile.mkdirs();
                } else {
                    // 创建父目录
                    new File(newFile.getParent()).mkdirs();
                    // 写入文件内容
                    try (FileOutputStream fos = new FileOutputStream(newFile)) {
                        int len;
                        while ((len = zis.read(buffer)) > 0) {
                            fos.write(buffer, 0, len);
                        }
                    }
                }
                zis.closeEntry();
            }
        }
    }
    public static void main(String[] args) {
        try {
            extract("D:/test/output.zip", "D:/test/unzip");
            System.out.println("解压完成!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

使用Apache Commons Compress库

1 添加Maven依赖

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-compress</artifactId>
    <version>1.24.0</version>
</dependency>

2 高级压缩功能

import org.apache.commons.compress.archivers.zip.*;
import org.apache.commons.compress.parallel.InputStreamSupplier;
import java.io.*;
import java.nio.file.*;
import java.util.zip.*;
public class AdvancedZipCompressor {
    /**
     * 使用自动检测的压缩方法压缩
     */
    public static void compressWithBestMethod(String sourcePath, String zipPath) 
            throws IOException {
        try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream(new FileOutputStream(zipPath))) {
            zos.setUseZip64(Zip64Mode.AsNeeded);
            File source = new File(sourcePath);
            compressRecursively(source, source.getName(), zos);
        }
    }
    private static void compressRecursively(File file, String entryName, 
            ZipArchiveOutputStream zos) throws IOException {
        if (file.isDirectory()) {
            // 创建目录条目
            ZipArchiveEntry dirEntry = new ZipArchiveEntry(entryName + "/");
            dirEntry.setMethod(ZipArchiveEntry.STORED);
            zos.putArchiveEntry(dirEntry);
            zos.closeArchiveEntry();
            File[] children = file.listFiles();
            if (children != null) {
                for (File child : children) {
                    compressRecursively(child, entryName + "/" + child.getName(), zos);
                }
            }
        } else {
            ZipArchiveEntry fileEntry = new ZipArchiveEntry(entryName);
            // 根据文件大小决定压缩方法
            FileInputStream fis = new FileInputStream(file);
            try {
                if (file.length() > 1024 * 1024) { // 大于1MB使用DEFLATED
                    fileEntry.setMethod(ZipArchiveEntry.DEFLATED);
                } else {
                    fileEntry.setMethod(ZipArchiveEntry.STORED);
                }
                zos.putArchiveEntry(fileEntry);
                byte[] buffer = new byte[8192];
                int len;
                while ((len = fis.read(buffer)) > 0) {
                    zos.write(buffer, 0, len);
                }
            } finally {
                fis.close();
                zos.closeArchiveEntry();
            }
        }
    }
    /**
     * 提取ZIP文件并保留权限信息
     */
    public static void extractWithPermissions(String zipPath, String destDir) 
            throws IOException {
        Path destPath = Paths.get(destDir).toAbsolutePath();
        Files.createDirectories(destPath);
        try (ZipFile zipFile = new ZipFile(new File(zipPath))) {
            zipFile.getEntries().asIterator().forEachRemaining(entry -> {
                try {
                    Path outputPath = destPath.resolve(entry.getName()).normalize();
                    // 安全检查
                    if (!outputPath.startsWith(destPath)) {
                        throw new IOException("非法路径: " + entry.getName());
                    }
                    if (entry.isDirectory()) {
                        Files.createDirectories(outputPath);
                    } else {
                        Files.createDirectories(outputPath.getParent());
                        try (InputStream is = zipFile.getInputStream(entry)) {
                            Files.copy(is, outputPath, StandardCopyOption.REPLACE_EXISTING);
                        }
                        // 设置文件权限
                        if (entry.getUnixMode() != 0) {
                            Files.setPosixFilePermissions(outputPath, 
                                convertUnixMode(entry.getUnixMode()));
                        }
                    }
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }
    }
    private static java.util.Set<java.nio.file.attribute.PosixFilePermission> 
            convertUnixMode(int mode) {
        java.util.Set<java.nio.file.attribute.PosixFilePermission> perms = 
            new java.util.HashSet<>();
        if ((mode & 0400) != 0) perms.add(java.nio.file.attribute.PosixFilePermission.OWNER_READ);
        if ((mode & 0200) != 0) perms.add(java.nio.file.attribute.PosixFilePermission.OWNER_WRITE);
        if ((mode & 0100) != 0) perms.add(java.nio.file.attribute.PosixFilePermission.OWNER_EXECUTE);
        if ((mode & 0040) != 0) perms.add(java.nio.file.attribute.PosixFilePermission.GROUP_READ);
        if ((mode & 0020) != 0) perms.add(java.nio.file.attribute.PosixFilePermission.GROUP_WRITE);
        if ((mode & 0010) != 0) perms.add(java.nio.file.attribute.PosixFilePermission.GROUP_EXECUTE);
        if ((mode & 0004) != 0) perms.add(java.nio.file.attribute.PosixFilePermission.OTHERS_READ);
        if ((mode & 0002) != 0) perms.add(java.nio.file.attribute.PosixFilePermission.OTHERS_WRITE);
        if ((mode & 0001) != 0) perms.add(java.nio.file.attribute.PosixFilePermission.OTHERS_EXECUTE);
        return perms;
    }
}

加密ZIP文件

1 使用Zip4j库(支持AES加密)

添加依赖:

<dependency>
    <groupId>net.lingala.zip4j</groupId>
    <artifactId>zip4j</artifactId>
    <version>2.11.5</version>
</dependency>
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.*;
import java.io.File;
import java.util.List;
public class EncryptedZipExample {
    /**
     * 创建加密ZIP文件
     */
    public static void createEncryptedZip(String sourcePath, String zipPath, 
            String password) throws Exception {
        ZipParameters zipParameters = new ZipParameters();
        // 设置加密
        zipParameters.setEncryptFiles(true);
        zipParameters.setEncryptionMethod(EncryptionMethod.ZIP_STANDARD_VARIANT_STRONG);
        zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_256);
        // 设置压缩
        zipParameters.setCompressionMethod(CompressionMethod.DEFLATE);
        zipParameters.setCompressionLevel(CompressionLevel.NORMAL);
        ZipFile zipFile = new ZipFile(zipPath, password.toCharArray());
        zipFile.setCharset(java.nio.charset.StandardCharsets.UTF_8);
        File source = new File(sourcePath);
        if (source.isDirectory()) {
            zipFile.addFolder(source, zipParameters);
        } else {
            zipFile.addFile(source, zipParameters);
        }
    }
    /**
     * 解密并解压ZIP文件
     */
    public static void decryptAndExtract(String zipPath, String password, 
            String destPath) throws Exception {
        ZipFile zipFile = new ZipFile(zipPath, password.toCharArray());
        // 验证密码
        if (!zipFile.isValidZipFile()) {
            throw new Exception("无效的ZIP文件");
        }
        if (zipFile.isEncrypted()) {
            // 尝试测试文件是否可读
            if (!zipFile.isValidZipFile()) {
                throw new Exception("密码错误或文件损坏");
            }
        }
        zipFile.extractAll(destPath);
    }
    /**
     * 添加文件到现有加密ZIP
     */
    public static void addFileToEncryptedZip(String zipPath, String password, 
            File fileToAdd) throws Exception {
        ZipFile zipFile = new ZipFile(zipPath, password.toCharArray());
        ZipParameters zipParameters = new ZipParameters();
        zipParameters.setEncryptFiles(true);
        zipParameters.setEncryptionMethod(EncryptionMethod.AES);
        zipParameters.setAesKeyStrength(AesKeyStrength.KEY_STRENGTH_256);
        zipFile.addFile(fileToAdd, zipParameters);
    }
    /**
     * 从加密ZIP中获取文件列表
     */
    public static List<net.lingala.zip4j.model.FileHeader> getFileList(
            String zipPath, String password) throws Exception {
        ZipFile zipFile = new ZipFile(zipPath, password.toCharArray());
        return zipFile.getFileHeaders();
    }
}

2 使用示例

public class ZipExample {
    public static void main(String[] args) {
        try {
            // 1. 基础压缩
            ZipCompressor.compress("D:/test/documents", "D:/test/documents.zip");
            // 2. 基础解压
            ZipExtractor.extract("D:/test/documents.zip", "D:/test/extracted");
            // 3. 高级压缩
            AdvancedZipCompressor.compressWithBestMethod(
                "D:/test/documents", "D:/test/advanced.zip");
            // 4. 加密压缩
            EncryptedZipExample.createEncryptedZip(
                "D:/test/documents", "D:/test/encrypted.zip", "myPassword123");
            // 5. 解密并解压
            EncryptedZipExample.decryptAndExtract(
                "D:/test/encrypted.zip", "myPassword123", "D:/test/decrypted");
            System.out.println("所有操作完成!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

实用工具类

import java.io.*;
import java.nio.file.*;
import java.util.zip.*;
public class ZipUtils {
    /**
     * 压缩单个文件
     */
    public static void compressSingleFile(String sourceFile, String zipFile) 
            throws IOException {
        File file = new File(sourceFile);
        try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))) {
            zos.putNextEntry(new ZipEntry(file.getName()));
            Files.copy(file.toPath(), zos);
            zos.closeEntry();
        }
    }
    /**
     * 压缩内存中的内容为ZIP
     */
    public static byte[] compressToBytes(Map<String, byte[]> files) 
            throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try (ZipOutputStream zos = new ZipOutputStream(baos)) {
            for (Map.Entry<String, byte[]> entry : files.entrySet()) {
                zos.putNextEntry(new ZipEntry(entry.getKey()));
                zos.write(entry.getValue());
                zos.closeEntry();
            }
        }
        return baos.toByteArray();
    }
    /**
     * 从ZIP中读取特定文件
     */
    public static byte[] extractFile(String zipPath, String fileName) 
            throws IOException {
        try (ZipFile zipFile = new ZipFile(zipPath)) {
            ZipEntry entry = zipFile.getEntry(fileName);
            if (entry == null) {
                throw new FileNotFoundException("文件不存在: " + fileName);
            }
            try (InputStream is = zipFile.getInputStream(entry)) {
                return is.readAllBytes();
            }
        }
    }
    /**
     * 检查ZIP文件是否有效
     */
    public static boolean isValidZip(String zipPath) {
        try (ZipFile zipFile = new ZipFile(zipPath)) {
            // 尝试读取中央目录
            zipFile.size();
            return true;
        } catch (IOException e) {
            return false;
        }
    }
    /**
     * 获取ZIP文件中的所有条目名称
     */
    public static List<String> listEntries(String zipPath) throws IOException {
        List<String> entries = new ArrayList<>();
        try (ZipFile zipFile = new ZipFile(zipPath)) {
            zipFile.stream().forEach(entry -> entries.add(entry.getName()));
        }
        return entries;
    }
    /**
     * 删除ZIP中的指定文件
     */
    public static void removeFileFromZip(String zipPath, String fileName) 
            throws IOException {
        Path tempFile = Files.createTempFile("zip", ".tmp");
        try (ZipFile originalZip = new ZipFile(zipPath);
             ZipOutputStream zos = new ZipOutputStream(
                 new FileOutputStream(tempFile.toFile()))) {
            byte[] buffer = new byte[1024];
            originalZip.stream()
                .filter(entry -> !entry.getName().equals(fileName))
                .forEach(entry -> {
                    try {
                        zos.putNextEntry(new ZipEntry(entry.getName()));
                        try (InputStream is = originalZip.getInputStream(entry)) {
                            int len;
                            while ((len = is.read(buffer)) > 0) {
                                zos.write(buffer, 0, len);
                            }
                        }
                        zos.closeEntry();
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                });
        }
        Files.move(tempFile, Paths.get(zipPath), 
            StandardCopyOption.REPLACE_EXISTING);
    }
}

这些示例涵盖了大多数常见的ZIP操作需求,根据您的具体使用场景,可以选择合适的方法,如果需要更多特定功能的实现,请告诉我具体需求。

抱歉,评论功能暂时关闭!