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

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

<!-- StopWatch耗時計算 -->
<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)同時支持壓縮多級文件夾,工具內(nèi)部做了遞歸處理
 * (3)碰到空的文件夾,也可以壓縮
 * (4)可以選擇是否保留原來的目錄結(jié)構(gòu)脖卖,如果不保留乒省,所有文件跑壓縮包根目錄去了,且空文件夾直接舍棄畦木。注意:如果不保留文件原來目錄結(jié)構(gòu)袖扛,在碰到文件名相同的文件時,會壓縮失敗十籍。
 * (5)代碼中提供了2個壓縮文件的方法蛆封,一個的輸入?yún)?shù)為文件夾路徑,一個為文件列表勾栗,可根據(jù)實際需求選擇方法惨篱。
 *  注意:
 * (1)支持選擇是否保留原來的文件目錄結(jié)構(gòu),如果不保留围俘,那么空文件夾直接不用處理砸讳。
 * (2)碰到空文件夾時,如果需要保留目錄結(jié)構(gòu)楷拳,則直接添加個ZipEntry就可以了绣夺,不過就是這個entry的名字后面需要帶上一斜杠(/)表示這個是目錄吏奸。
 * (3)遞歸時欢揖,不需要把zip輸出流關(guān)閉,zip輸出流的關(guān)閉應(yīng)該是在調(diào)用完遞歸方法后面關(guān)閉
 * (4)遞歸時奋蔚,如果是個文件夾且需要保留目錄結(jié)構(gòu)她混,那么在調(diào)用方法壓縮他的子文件時,需要把文件夾的名字加一斜杠給添加到子文件名字前面泊碑,這樣壓縮后才有多級目錄坤按。
 * @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("測試開始!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
        // 1
        // 壓縮后的文件
        FileOutputStream fileOutputStream1 = new FileOutputStream("/Users/luoyu/Downloads/test.zip");
        ZipUtils.toZip("/Users/luoyu/Downloads/日報內(nèi)容.txt", fileOutputStream1,true);

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

    /**
     * 單個
     * @param srcDir 要壓縮文件路徑
     * @param out    壓縮后文件輸出流
     * @param KeepDirStructure  是否保留原來的目錄結(jié)構(gòu),true:保留目錄結(jié)構(gòu);
     *                          false:所有文件跑到壓縮包根目錄下(注意:不保留目錄結(jié)構(gòu)可能會出現(xiàn)同名文件,會壓縮失敗)
     */
    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("壓縮完成,耗時:{}馒过。", (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 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("壓縮完成腹忽,耗時:{}来累。", (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)可能會出現(xiàn)同名文件,會壓縮失敗)
     */
    private static void compress(File sourceFile, ZipOutputStream zos, String name,
                                 boolean KeepDirStructure) throws Exception{
        byte[] buf = new byte[BUFFER_SIZE];
        if(sourceFile.isFile()){
            // 向zip輸出流中添加一個zip實體嘹锁,構(gòu)造器中name為zip實體的文件的名字
            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)時,需要對空文件夾進(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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末领猾,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌摔竿,老刑警劉巖面粮,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異继低,居然都是意外死亡但金,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門郁季,熙熙樓的掌柜王于貴愁眉苦臉地迎上來冷溃,“玉大人,你說我怎么就攤上這事梦裂∷普恚” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵年柠,是天一觀的道長凿歼。 經(jīng)常有香客問我,道長冗恨,這世上最難降的妖魔是什么答憔? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮掀抹,結(jié)果婚禮上虐拓,老公的妹妹穿的比我還像新娘。我一直安慰自己傲武,他們只是感情好蓉驹,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著揪利,像睡著了一般态兴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上疟位,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天瞻润,我揣著相機(jī)與錄音,去河邊找鬼甜刻。 笑死绍撞,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的罢吃。 我是一名探鬼主播楚午,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼尿招!你這毒婦竟也來了矾柜?” 一聲冷哼從身側(cè)響起阱驾,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎怪蔑,沒想到半個月后里覆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缆瓣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年喧枷,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弓坞。...
    茶點(diǎn)故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡隧甚,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出渡冻,到底是詐尸還是另有隱情戚扳,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布族吻,位于F島的核電站帽借,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏超歌。R本人自食惡果不足惜砍艾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望巍举。 院中可真熱鬧脆荷,春花似錦、人聲如沸禀综。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽定枷。三九已至,卻和暖如春届氢,著一層夾襖步出監(jiān)牢的瞬間欠窒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工退子, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留岖妄,地道東北人。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓寂祥,卻偏偏與公主長得像荐虐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子丸凭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容