Java將文件壓縮為zip格式及解壓

第一步,導(dǎo)入maven依賴

<!-- StopWatch耗時(shí)計(jì)算 -->
<dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.6</version>
</dependency>

第二步,創(chuàng)建并編寫ZipUtils類,運(yùn)行main方法查看效果,如下

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.time.StopWatch;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 *  說明:
 * (1)可以壓縮文件,也可以壓縮文件夾
 * (2)同時(shí)支持壓縮多級(jí)文件夾,工具內(nèi)部做了遞歸處理
 * (3)碰到空的文件夾,也可以壓縮
 * (4)可以選擇是否保留原來的目錄結(jié)構(gòu),如果不保留,所有文件跑壓縮包根目錄去了,且空文件夾直接舍棄。注意:如果不保留文件原來目錄結(jié)構(gòu),在碰到文件名相同的文件時(shí),會(huì)壓縮失敗。
 * (5)代碼中提供了2個(gè)壓縮文件的方法,一個(gè)的輸入?yún)?shù)為文件夾路徑,一個(gè)為文件列表,可根據(jù)實(shí)際需求選擇方法。
 *  注意:
 * (1)支持選擇是否保留原來的文件目錄結(jié)構(gòu),如果不保留,那么空文件夾直接不用處理。
 * (2)碰到空文件夾時(shí),如果需要保留目錄結(jié)構(gòu),則直接添加個(gè)ZipEntry就可以了,不過就是這個(gè)entry的名字后面需要帶上一斜杠(/)表示這個(gè)是目錄。
 * (3)遞歸時(shí),不需要把zip輸出流關(guān)閉,zip輸出流的關(guān)閉應(yīng)該是在調(diào)用完遞歸方法后面關(guān)閉
 * (4)遞歸時(shí),如果是個(gè)文件夾且需要保留目錄結(jié)構(gòu),那么在調(diào)用方法壓縮他的子文件時(shí),需要把文件夾的名字加一斜杠給添加到子文件名字前面,這樣壓縮后才有多級(jí)目錄。
 * @author  jhx
 * @date    2021年2月121日 下午7:16:08
 * @version v1.0
 */
@Slf4j
public class ZipUtils {

    private static final int  BUFFER_SIZE = 2 * 1024;

    public static void main(String[] args) throws Exception {
        log.info("測(cè)試開始!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
        // 1
        // 壓縮后的文件
        FileOutputStream fileOutputStream1 = new FileOutputStream("/Users/luoyu/Downloads/test.zip");
        ZipUtils.toZip("/Users/luoyu/Downloads/日?qǐng)?bào)內(nèi)容.txt", fileOutputStream1,true);

        // 2
        List<File> fileList = new ArrayList<>();
        fileList.add(new File("/Users/luoyu/Downloads/日?qǐng)?bào)內(nèi)容1.txt"));
        fileList.add(new File("/Users/luoyu/Downloads/日?qǐng)?bào)內(nèi)容2.txt"));
        FileOutputStream fileOutputStream2 = new FileOutputStream("/Users/luoyu/Downloads/test.zip");
        ZipUtils.toZip(fileList, fileOutputStream2);
        log.info("測(cè)試結(jié)束!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
    }

    /**
     * 單個(gè)
     * @param srcDir 要壓縮文件路徑
     * @param out    壓縮后文件輸出流
     * @param KeepDirStructure  是否保留原來的目錄結(jié)構(gòu),true:保留目錄結(jié)構(gòu);
     *                          false:所有文件跑到壓縮包根目錄下(注意:不保留目錄結(jié)構(gòu)可能會(huì)出現(xiàn)同名文件,會(huì)壓縮失敗)
     */
    public static void toZip(String srcDir, OutputStream out, boolean KeepDirStructure)
            throws Exception{
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ZipOutputStream zos = null ;
        try {
            zos = new ZipOutputStream(out);
            File sourceFile = new File(srcDir);
            compress(sourceFile, zos, sourceFile.getName(), KeepDirStructure);
            stopWatch.stop();
            log.info("壓縮完成,耗時(shí):{}。", (double) stopWatch.getTime()/1000 + "s");
        } catch (Exception e) {
            throw new Exception("壓縮失敗:" + e);
        }finally{
            if(zos != null){
                try {
                    zos.close();
                } catch (Exception e) {
                    log.error("壓縮失?。? + e);
                }
            }
        }
    }

    /**
     * 多個(gè)
     * @param srcFiles 需要壓縮的文件列表
     * @param out           壓縮后文件輸出流
     */
    public static void toZip(List<File> srcFiles , OutputStream out)throws Exception {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ZipOutputStream zos = null ;
        try {
            zos = new ZipOutputStream(out);
            for (File srcFile : srcFiles) {
                byte[] buf = new byte[BUFFER_SIZE];
                zos.putNextEntry(new ZipEntry(srcFile.getName()));
                int len;
                FileInputStream in = new FileInputStream(srcFile);
                while ((len = in.read(buf)) != -1){
                    zos.write(buf, 0, len);
                }
                zos.closeEntry();
                in.close();
            }
            stopWatch.stop();
            log.info("壓縮完成,耗時(shí):{}。", (double) stopWatch.getTime()/1000 + "s");
        } catch (Exception e) {
            throw new Exception("壓縮失敗:" + e);
        }finally{
            if(zos != null){
                try {
                    zos.close();
                } catch (Exception e) {
                    log.error("壓縮失?。? + e);
                }
            }
        }
    }

    /**
     * 遞歸壓縮方法
     * @param sourceFile 源文件
     * @param zos        zip輸出流
     * @param name       壓縮后的名稱
     * @param KeepDirStructure  是否保留原來的目錄結(jié)構(gòu),true:保留目錄結(jié)構(gòu);
     *                          false:所有文件跑到壓縮包根目錄下(注意:不保留目錄結(jié)構(gòu)可能會(huì)出現(xiàn)同名文件,會(huì)壓縮失敗)
     */
    private static void compress(File sourceFile, ZipOutputStream zos, String name,
                                 boolean KeepDirStructure) throws Exception{
        byte[] buf = new byte[BUFFER_SIZE];
        if(sourceFile.isFile()){
            // 向zip輸出流中添加一個(gè)zip實(shí)體,構(gòu)造器中name為zip實(shí)體的文件的名字
            zos.putNextEntry(new ZipEntry(name));
            // copy文件到zip輸出流中
            int len;
            FileInputStream in = new FileInputStream(sourceFile);
            while ((len = in.read(buf)) != -1){
                zos.write(buf, 0, len);
            }
            // Complete the entry
            zos.closeEntry();
            in.close();
        } else {
            File[] listFiles = sourceFile.listFiles();
            if(listFiles == null || listFiles.length == 0){
                // 需要保留原來的文件結(jié)構(gòu)時(shí),需要對(duì)空文件夾進(jìn)行處理
                if(KeepDirStructure){
                    // 空文件夾的處理
                    zos.putNextEntry(new ZipEntry(name + "/"));
                    // 沒有文件,不需要文件的copy
                    zos.closeEntry();
                }
            }else {
                for (File file : listFiles) {
                    // 判斷是否需要保留原來的文件結(jié)構(gòu)
                    if (KeepDirStructure) {
                        // 注意:file.getName()前面需要帶上父文件夾的名字加一斜杠,
                        // 不然最后壓縮包中就不能保留原來的文件結(jié)構(gòu),即:所有文件都跑到壓縮包根目錄下了
                        compress(file, zos, name + "/" + file.getName(),KeepDirStructure);
                    } else {
                        compress(file, zos, file.getName(),KeepDirStructure);
                    }
                }
            }
        }
    }

}

完整代碼地址:https://github.com/Jinhx128/java-demo

注:此工程包含多個(gè)包,本文所用代碼均在com.luoyu.java.zip包下

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容