Skip to main content
 首页 » 编程设计

Java解压缩文件

2022年07月19日130webabcd

Java解压缩文件

本文我们讨论如何解压缩文件。java核心库提供了一些实用工具,java.util.zip包中可以找到所有压缩和解压相关工具。

1. 压缩文件

包括单个文件、多个文件以及压缩目录。

1.1. 单个文件

首先看个简单操作————压缩单个文件,即把源文件test1.txt压缩为归档文件compressed.zip。
当然首先从磁盘读文件,test1.txt在gradle项目的resouces目录下:

public class ZipDemo { 
    public static void main(String[] args) throws IOException, URISyntaxException { 
        String sourceFile = "test1.txt"; 
        URL resource = ZipDemo.class.getClassLoader().getResource(sourceFile); 
        File fileToZip = new File(resource.toURI()); 
        FileInputStream fis = new FileInputStream(fileToZip); 
        ZipEntry zipEntry = new ZipEntry(fileToZip.getName()); 
 
        Path targget = Paths.get(fileToZip.getParent(), "compressed.zip"); 
 
        FileOutputStream fos = new FileOutputStream(targget.toFile()); 
        ZipOutputStream zipOut = new ZipOutputStream(fos); 
        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(); 
    } 
} 

生成的目标归档文件在相同目录下,build中。

1.2. 压缩多个文件

接下来看如何压缩多个文件:

public class ZipMultipleFiles { 
    public static void main(String[] args) throws IOException { 
        List<String> 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(); 
    } 
} 

1.3. 压缩目录

让我们讨论如何压缩整个目录:

public class ZipDirectory { 
    public static void main(String[] args) throws IOException { 
        String sourceDir = "zipTest"; 
        FileOutputStream fos = new FileOutputStream("dirCompressed.zip"); 
        ZipOutputStream zipOut = new ZipOutputStream(fos); 
        File fileToZip = new File(sourceDir); 
  
        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(File.pathSeparator)) { 
                 fileName = fileName + File.pathSeparator; 
            } 
            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(); 
    } 
} 

可能有子目录,这里需要递归进行迭代。
每次发现目录,在子ZipEntity中增加其名称用于保存层次。
我们也给空目录创建目录项。

2. 解压

解压 compressed.zip 至新的文件夹nuzipTest:

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) { 
            File newFile = newFile(destDir, zipEntry); 
            FileOutputStream fos = new FileOutputStream(newFile); 
            int len; 
            while ((len = zis.read(buffer)) > 0) { 
                fos.write(buffer, 0, len); 
            } 
            fos.close(); 
            zipEntry = zis.getNextEntry(); 
        } 
        zis.closeEntry(); 
        zis.close(); 
    } 
      
    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; 
    } 
} 

另一个关键点是在newFile()方法中防止将文件写入目标文件夹外的文件系统,该问题称为Zip Slip漏洞。

3. 总结

本文介绍如何利用Java核心库实现解压缩文件功能,读者也可以使用第三方库Zip4j尝试更多功能。


本文参考链接:https://blog.csdn.net/neweastsun/article/details/103106475
阅读延展