java压缩解压缩

一.压缩为zip

使用Java提供的核心库,java.util.zip

1.压缩多个文件

public class ZipMultipleFiles {
    
    public static void main(String[] args) throws IOException {
        
        // 文件所在的路径
        List<String> srcFiles = Arrays.asList(
            "src/main/resources/test1.txt", 
            "src/main/resources/test2.txt"
        );
        
        // 构造压缩文件对象
        FileOutputStream fos = new FileOutputStream("src/main/resources/multiCompressed.zip");
        ZipOutputStream zipOut = new ZipOutputStream(fos);
        
        // 向压缩包对象中添加多个文件
        for (String srcFile : srcFiles) {
            File fileToZip = new File(srcFile);
            ZipEntry zipEntry = new ZipEntry(fileToZip.getName());
            zipOut.putNextEntry(zipEntry);
			
            FileInputStream fis = new FileInputStream(fileToZip);
            byte[] bytes = new byte[1024];
            int length;
            while((length = fis.read(bytes)) >= 0) {
                // 将文件信息写入压缩文件中
                zipOut.write(bytes, 0, length);
            }
            fis.close();
        }
        
        zipOut.close();
        fos.close();
    }
}

2.压缩目录

  • 要压缩子目录及其子目录文件,所以需要递归遍历
  • 每次遍历找到的是目录时,我们都将其名称附加“/”,并将其以ZipEntry保存到压缩包中,从而保持压缩的目录结构。
  • 每次遍历找到的是文件时,将其以字节码形式压缩到压缩包里面
public class ZipDirectory {
    
    public static void main(String[] args) throws IOException, FileNotFoundException {
        
        // 需要被压缩的文件夹
        String sourceFile = "src/main/resources/zipTest";
        
        // 文件夹压缩之后的文件夹对象
        FileOutputStream fos = new FileOutputStream("src/main/resources/dirCompressed.zip");
        ZipOutputStream zipOut = new ZipOutputStream(fos);
        
        // 递归压缩文件夹
        File fileToZip = new File(sourceFile);
        zipFile(fileToZip, fileToZip.getName(), zipOut);
        
        // 关闭输出流
        zipOut.close();
        fos.close();
    }

    /**
     * 将fileToZip文件夹及其子目录文件递归压缩到zip文件中
     * @param fileToZip 递归当前处理对象,可能是文件夹,也可能是文件
     * @param fileName fileToZip文件或文件夹名称
     * @param zipOut 压缩文件输出流
     * @throws IOException
     */
    private static void zipFile(File fileToZip, String fileName, ZipOutputStream zipOut) throws IOException {
        // 不压缩隐藏文件夹
        if (fileToZip.isHidden()) {
            return;
        }
        // 判断压缩对象如果是一个文件夹
        if (fileToZip.isDirectory()) {
            
            if (fileName.endsWith("/")) {
                // 如果文件夹是以“/”结尾,将文件夹作为压缩箱放入zipOut压缩输出流
                zipOut.putNextEntry(new ZipEntry(fileName));
                zipOut.closeEntry();
            } else {
                // 如果文件夹不是以“/”结尾,将文件夹结尾加上“/”之后作为压缩箱放入zipOut压缩输出流
                zipOut.putNextEntry(new ZipEntry(fileName + "/"));
                zipOut.closeEntry();
            }
            
            // 遍历文件夹子目录,进行递归的zipFile
            File[] children = fileToZip.listFiles();
            for (File childFile : children) {
                zipFile(childFile, fileName + "/" + childFile.getName(), zipOut);
            }
            //如果当前递归对象是文件夹,加入ZipEntry之后就返回
            return;
        }
        
        // 如果当前的fileToZip不是一个文件夹,是一个文件,将其以字节码形式压缩到压缩包里面
        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();
    }
    
}

二.zip解压缩

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));
        // 获取压缩包中的entry,并将其解压
        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();
            //解压完成一个entry,再解压下一个
            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("该解压项在目标文件夹之外: " + zipEntry.getName());
        }

        return destFile;
    }
}

三.压缩为tar.gz

java中没有一种官方的API可以去创建tar.gz文件。所以我们需要使用到第三方库Apache Commons Compress去创建.tar.gz文件。

  1. tar文件准确的说是打包文件,将文件打包到一个tar文件中,文件名后缀是.tar
  2. Gzip是将文件的存储空间压缩保存,文件名后缀是.gz
  3. tar.gz.tgz通常是指将文件打包到一个tar文件中,并将它使用Gzip进行压缩。

maven坐标

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

1.压缩多个文件

import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
import org.junit.jupiter.api.Test;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;

public class TarGzTest {

    @Test
    void testFilesTarGzip() throws IOException {
        
        // 输入文件,被压缩文件
        Path path1 = Paths.get("/home/test/file-a.xml");
        Path path2 = Paths.get("/home/test/file-b.txt");
        List<Path> paths = Arrays.asList(path1, path2);

        //输出文件压缩结果
        Path output = Paths.get("/home/test/output.tar.gz");

        // OutputStream输出流、BufferedOutputStream缓冲输出流
        // GzipCompressorOutputStream是gzip压缩输出流
        // TarArchiveOutputStream打tar包输出流(包含gzip压缩输出流)
        try (OutputStream fOut = Files.newOutputStream(output);
             BufferedOutputStream buffOut = new BufferedOutputStream(fOut);
             GzipCompressorOutputStream gzOut = new GzipCompressorOutputStream(buffOut);
             TarArchiveOutputStream tOut = new TarArchiveOutputStream(gzOut)) {

            // 遍历文件list
            for (Path path : paths) {
                
                // 该文件不是目录或者符号链接
                if (!Files.isRegularFile(path)) {
                    throw new IOException("Support only file!");
                }
                // 将该文件放入tar包,并执行gzip压缩
                TarArchiveEntry tarEntry = new TarArchiveEntry(
                    path.toFile(),
                    path.getFileName().toString());

                tOut.putArchiveEntry(tarEntry);
                Files.copy(path, tOut);

                tOut.closeArchiveEntry();
            }
            // for循环完成之后,finish-tar包输出流
            tOut.finish();
        }
    }
}

2.压缩目录

@Test
void testDirTarGzip() throws IOException {
    // 被压缩打包的文件夹
    Path source = Paths.get("/home/test");
    // 如果不是文件夹抛出异常
    if (!Files.isDirectory(source)) {
        throw new IOException("请指定一个文件夹");
    }

    // 压缩之后的输出文件名称
    String tarFileName = "/home/" + source.getFileName().toString() + ".tar.gz";

    // OutputStream输出流、BufferedOutputStream缓冲输出流
    // GzipCompressorOutputStream是gzip压缩输出流
    // TarArchiveOutputStream打tar包输出流(包含gzip压缩输出流)
    try (OutputStream fOut = Files.newOutputStream(Paths.get(tarFileName));
         BufferedOutputStream buffOut = new BufferedOutputStream(fOut);
         GzipCompressorOutputStream gzOut = new GzipCompressorOutputStream(buffOut);
         TarArchiveOutputStream tOut = new TarArchiveOutputStream(gzOut)) {
        
        // 遍历文件目录树
        Files.walkFileTree(source, new SimpleFileVisitor<Path>() {
            
            //当成功访问到一个文件
            @Override
            public FileVisitResult visitFile(Path file,
                                             BasicFileAttributes attributes) throws IOException {

                // 判断当前遍历文件是不是符号链接(快捷方式),不做打包压缩处理
                if (attributes.isSymbolicLink()) {
                    return FileVisitResult.CONTINUE;
                }

                // 获取当前遍历文件名称
                Path targetFile = source.relativize(file);

                // 将该文件打包压缩
                TarArchiveEntry tarEntry = new TarArchiveEntry(
                    file.toFile(), targetFile.toString());
                tOut.putArchiveEntry(tarEntry);
                Files.copy(file, tOut);
                tOut.closeArchiveEntry();
                // 继续下一个遍历文件处理
                return FileVisitResult.CONTINUE;
            }

            // 当前遍历文件访问失败
            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) {
                System.err.printf("无法对该文件压缩打包为tar.gz : %s%n%s%n", file, exc);
                return FileVisitResult.CONTINUE;
            }

        });
        
        // for循环完成之后,finish-tar包输出流
        tOut.finish();
    }
}

四.tar.gz解压缩

@Test
public void testDeCompressTarGzip() throws IOException {
    
    // 解压文件
    Path source = Paths.get("/home/test/output.tar.gz");
    // 解压到哪
    Path target = Paths.get("/home/test2");

    if (Files.notExists(source)) {
        throw new IOException("您要解压的文件不存在");
    }

    // InputStream输入流,以下四个流将tar.gz读取到内存并操作
    // BufferedInputStream缓冲输入流
    // GzipCompressorInputStream解压输入流
    // TarArchiveInputStream解tar包输入流
    try (InputStream fi = Files.newInputStream(source);
         BufferedInputStream bi = new BufferedInputStream(fi);
         GzipCompressorInputStream gzi = new GzipCompressorInputStream(bi);
         TarArchiveInputStream ti = new TarArchiveInputStream(gzi)) {

        ArchiveEntry entry;
        while ((entry = ti.getNextEntry()) != null) {

            // 获取解压文件目录,并判断文件是否损坏
            Path newPath = zipSlipProtect(entry, target);
            if (entry.isDirectory()) {
                // 创建解压文件目录
                Files.createDirectories(newPath);
            } else {
                // 再次校验解压文件目录是否存在
                Path parent = newPath.getParent();
                if (parent != null) {
                    if (Files.notExists(parent)) {
                        Files.createDirectories(parent);
                    }
                }
                // 将解压文件输入到TarArchiveInputStream,输出到磁盘newPath目录
                Files.copy(ti, newPath, StandardCopyOption.REPLACE_EXISTING);
            }
        }
    }
}

// 判断压缩文件是否被损坏,并返回该文件的解压目录
private  Path zipSlipProtect(ArchiveEntry entry,Path targetDir)
    throws IOException {

    Path targetDirResolved = targetDir.resolve(entry.getName());
    Path normalizePath = targetDirResolved.normalize();

    if (!normalizePath.startsWith(targetDir)) {
        throw new IOException("压缩文件已被损坏: " + entry.getName());
    }

    return normalizePath;
}

转载自:
1.http://www.zimug.com/java/%e4%bd%bf%e7%94%a8java-api%e8%bf%9b%e8%a1%8czip%e9%80%92%e5%bd%92%e5%8e%8b%e7%bc%a9%e6%96%87%e4%bb%b6%e5%a4%b9%e4%bb%a5%e5%8f%8a%e8%a7%a3%e5%8e%8b/.html
2.http://www.zimug.com/java/%e4%bd%bf%e7%94%a8java-api%e8%bf%9b%e8%a1%8ctar-gz%e6%96%87%e4%bb%b6%e5%8f%8a%e6%96%87%e4%bb%b6%e5%a4%b9%e5%8e%8b%e7%bc%a9%e8%a7%a3%e5%8e%8b%e7%bc%a9/.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java实现压缩解压缩ZIP   import java.io.BufferedInputStream;   import java.io.BufferedOutputStream;   import java.io.File;   import java.io.FileInputStream;   import java.io.FileOutputStream;   import java.util.zip.ZipEntry;   import java.util.zip.ZipOutputStream;   public class Zip {   static final int BUFFER = 2048;   public static void main(String argv[]) {   try {   BufferedInputStream origin = null;   FileOutputStream dest = new FileOutputStream("E:\\test\\myfiles.zip");   ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(   dest));   byte data[] = new byte[BUFFER];   File f = new File("e:\\test\\a\\");   File files[] = f.listFiles();   for (int i = 0; i < files.length; i++) {   FileInputStream fi = new FileInputStream(files[i]);   origin = new BufferedInputStream(fi, BUFFER);   ZipEntry entry = new ZipEntry(files[i].getName());   out.putNextEntry(entry);   int count;   while ((count = origin.read(data, 0, BUFFER)) != -1) {   out.write(data, 0, count);   }   origin.close();   }   out.close();   } catch (Exception e) {   e.printStackTrace();   }   }   }   解压缩的   import java.io.BufferedInputStream;   import java.io.BufferedOutputStream;   import java.io.File;   import java.io.FileOutputStream;   import java.util.Enumeration;   import java.util.zip.ZipEntry;   import java.util.zip.ZipFile;   public class UnZip {   static final int BUFFER = 2048;   public static void main(String argv[]) {   try {   String fileName = "E:\\test\\myfiles.zip";   String filePath = "E:\\test\\";   ZipFile zipFile = new ZipFile(fileName);   Enumeration emu = zipFile.entries();   int i=0;   while(emu.hasMoreElements()){   ZipEntry entry = (ZipEntry)emu.nextElement();   //会把目录作为一个file读出一次,所以只建立目录就可以,之下的文件还会被迭代到。   if (entry.isDirectory())   {   new File(filePath + entry.getName()).mkdirs();   continue;   }   BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(entry));   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值