文件较复杂操作: 打包、解压

本文详细介绍使用Java标准库中的`java.util.zip.ZipOutputStream`和`ZipInputStream`进行文件的压缩与解压缩操作。包括单个文件、文件夹及多个文件的压缩方法,并演示了解压缩过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package javaFileStudy;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * 文件较复杂操作: 打包、解压
 *
 * 目标
 * 1、使用java.util.zip.ZipOutputStream 进行压缩 (压缩单个文件、单个文件夹(全文件或目录文件)、多个文件)
 * 2、使用java.util.zip.ZipInputStream 进行解压
 * 3、使用org.apache.tools.zipZipOutputStream 进行压缩,并了解他是如何解决java.util.zip.ZipOutputStream压缩后文件名乱码的
 * 答:jdk1.7就自带编码指定,解决乱码。new ZipOutputStream(new FileOutputStream(zipFile), Charset.forName("GBK"))
 *
 * 知识科普 :
 * 1、压缩包:相当于 ZipEntry的容器
 * 2、压缩:使用java.util.zip.ZipOutputStream(目标文件输出流).putZipEntry(),向zip文件中创建ZipEntry,然后写入数据(类似Map.put)
 * 3、解压:依次取出zip文件中的ZipEntry内容写入到新的文件中
 * 4、在java处理中,一般把文件创建在临时目录中System.getPorperty("java.io")中进行使用,服务器重启就没了。
 *
 * @author xubo
 *
 */
public class File2 {

    public static void main(String args[]) throws IOException {
        // String filepath = "second/three/second/File.txt";
        // String zipFilepath = "second/zipFile.zip"; // 必须正确文件路径,因为打包里面没有进行判断。 创建文件使用File1.create就可以随意了
        // compressFile(new File(filepath), new File(zipFilepath));

        // 再将"second下的所有文件进行压缩到first下面" (建议自己拼的路径用下面的方式创建文件)
        compressFile(Paths.get("second").toFile(), Paths.get("first/second.zip").toFile());

        // 再测试压缩多个文件 , 直接写文件,那么应该不存在文件夹
        /*
         * File file1 = Paths.get("second/three/second/File.txt").toFile();
         * File file2 = Paths.get("second/zipFile.zip").toFile();
         * File zipFile = Paths.get("first/second2.zip").toFile();
         * File[] files = new File[2];
         * files[0] = file1;
         * files[1] = file2;
         * compressFiles(files, zipFile);
         */

        // 将刚压缩的文件解压到"three"
        File zipFile = Paths.get("first/second.zip").toFile();
        decompressFile(zipFile, "three2");
    }

    /**
     * java.util.zip.ZipOutputStream压缩单个文件
     *
     * @throws IOException
     *
     */
    static File compressFile(File file, File zipFile) throws IOException {
        ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile)); // 构建Zip输出流
        compressSingeFile(file, zos);
        zos.flush();
        zos.close(); // 不需要指明ZOS关闭,因为包装流关闭,内部流也会关闭。
        return zipFile;
    }

    /**
     * 压缩单个文件单独处理
     * zos请自行flush()和close()处理
     *
     * @throws IOException
     */
    private static void compressSingeFile(File file, ZipOutputStream zos) throws IOException {
        compressSingeFile(file, zos, null);
    }

    /**
     * 压缩单个文件单独处理,供循环调用
     *
     * @param file
     *            原来的文件
     * @param zos
     *            zipFile的输出流
     * @param separatePosition
     *            文件绝对路径需要截断的位置,用来保存文件名称
     * @throws IOException
     */
    private static void compressSingeFile(File file, ZipOutputStream zos, Integer separatePosition) throws IOException {
        separatePosition = separatePosition == null ? (file.getAbsolutePath().lastIndexOf(File.separator) + 1) : separatePosition;// 初始化路径隔断
        if (file.isFile()) { // 是个正常文件,不是目录
            compressNormalFile(file, zos, separatePosition);
        } else if (file.listFiles().length == 0) { // 空文件夹
            // compressEmptyDirectory(file, zos, separatePosition); 这个不行,被网上的某高手骗了
        } else { // 含有内容的文件夹,循环处理
            File[] files = file.listFiles();
            if (files != null && files.length > 0) { // 空文件夹暂时不处理
                for (File sf : files) {
                    compressSingeFile(sf, zos, separatePosition);
                }
            }
        }
    }

    /**
     * 压缩一个正常文件
     *
     * @param file
     * @param zos
     * @param separatePosition
     * @throws IOException
     */
    private static void compressNormalFile(File file, ZipOutputStream zos, Integer separatePosition) throws IOException {
        String entryPath = file.getAbsolutePath().substring(separatePosition);
        compressToPointedZipEnrty(file, zos, entryPath);
    }

    /**
     * 压缩一个空文件夹
     *
     * @param file
     * @param zos
     * @param separatePosition
     * @throws IOException
     */
    private static void compressEmptyDirectory(File file, ZipOutputStream zos, Integer separatePosition) throws IOException { // 压缩空文件夹
        String entryPath = file.getAbsolutePath().substring(separatePosition) + File.separator;
        compressToPointedZipEnrty(file, zos, entryPath);
    }

    /**
     * 压缩文件到一个指定名称的zipEntry
     *
     * @param file
     * @param zos
     * @param zipEntryName
     * @throws IOException
     */
    private static void compressToPointedZipEnrty(File file, ZipOutputStream zos, String zipEntryName) throws IOException { // 压缩空文件夹
        FileInputStream fis = new FileInputStream(file);
        zos.putNextEntry(new ZipEntry(zipEntryName));
        byte[] b = new byte[2000];
        int tmp = 0;
        if ((tmp = fis.read(b)) != -1) {
            zos.write(b, 0, tmp);
        }
        fis.close(); // 哪里创建的流哪里关闭
    }

    /**
     * java.util.zip.ZipOutputStream压缩多个文件
     *
     * @throws IOException
     */
    static File compressFiles(File[] files, File zipFile) throws IOException {
        if (files.length > 0) {
            ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile), Charset.forName("GBK"));
            for (File file : files) {
                compressSingeFile(file, zos);
            }
            zos.flush();
            zos.close();
        }
        return zipFile;
    }

    /**
     * 解压文件到目录directoryPath下面
     *
     * @param file
     * @param directoryPath
     * @return
     * @throws IOException
     */
    static List<File> decompressFile(File zipFile, String directoryPath) throws IOException {
        List<File> result = new ArrayList<File>();
        File directory = new File(directoryPath);
        if (!directory.exists()) { // 目录不存在
            directory.mkdirs();
        }
        ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile));
        ZipEntry zipEntry = null;
        while ((zipEntry = zis.getNextEntry()) != null) { // 便利zipFile中的zipEntry
            File sFile = new File(directory.getAbsolutePath() + File.separator + zipEntry.getName());
            System.out.println(zipEntry.getName());
            // 这有个坑,如果是多层文件夹嵌套可能文件路径不存在,得校验
            if (!sFile.getParentFile().exists()) {
                sFile.getParentFile().mkdirs();
            }
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(sFile));
            byte[] b = new byte[2000];
            int tmp = 0;
            while ((tmp = zis.read(b)) != -1) {
                bos.write(b, 0, tmp);
            }
            bos.flush();
            bos.close();
            zis.closeEntry();
            result.add(sFile);
        }
        zis.close();
        return result;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值