Java壓縮技術之解壓篇,支持:ZIP、RAR、7Z、TAR、GZ、TAR.GZ、BZ2、TAR.BZ2


轉載自:https://blog.csdn.net/qq_28082757/article/details/78932756

這篇文章主要講解Java解壓的操作,后續會寫一篇關於壓縮的文章。

提醒:文章中有些片段看似代碼很多,其實去除trycatch、釋放資源真正有用的代碼沒幾句,解壓其實都很簡單,主要用心去觀察,都是依葫蘆畫瓢。

首先,先寫一個類似輔助的視圖類:

public enum FileType {
    // 未知
    UNKNOWN,
    // 壓縮文件
    ZIP, RAR, _7Z, TAR, GZ, TAR_GZ, BZ2, TAR_BZ2,
    // 位圖文件
    BMP, PNG, JPG, JPEG,
    // 矢量圖文件
    SVG,
    // 影音文件
    AVI, MP4, MP3, AAR, OGG, WAV, WAVE
}

這個類主要是用來將各種文件的類型集中管理,當然,不寫這個類也是可以的,可以直接用字符串去表示。

然后,我還寫了一個獲取文件真實類型的方法,為什么要寫這個方法呢?因為,我們是可以直接去修改文件的后綴的,這樣很危險!

本博客博主按:根據文件頭檢測文件類型+文件擴展名是比較嚴謹的辦法。

但是一些特殊情況可能是例外:例如千千靜聽,等軟件皮膚是zip文件,openoffice格式文件也是zip壓縮的,盡管他是xlsx格式的

   /**
     * 獲取文件真實類型
     *
     * @param file 要獲取類型的文件。
     * @return 文件類型枚舉。
     */
    private static FileType getFileType(File file){
        FileInputStream inputStream =null;
        try{
            inputStream = new FileInputStream(file);
            byte[] head = new byte[4];
            if (-1 == inputStream.read(head)) {
                return FileType.UNKNOWN;
            }
            int headHex = 0;
            for (byte b : head) {
                headHex <<= 8;
                headHex |= b;
            }
            switch (headHex) {
                case 0x504B0304:
                    return FileType.ZIP;
                case 0x776f7264:
                    return FileType.TAR;
                case -0x51:
                    return FileType._7Z;
                case 0x425a6839:
                    return FileType.BZ2;
                case -0x74f7f8:
                    return FileType.GZ;
                case 0x52617221:
                    return FileType.RAR;
                default:
                    return FileType.UNKNOWN;
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                if(inputStream!=null){
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return FileType.UNKNOWN;
    }

這里是通過文件頭信息來判斷什么類型的。其他文件的頭文件信息,這里就不展示了。如果有需要,可以拿文件來跑跑,看看headHex是啥值就行了。

最后還有一個創建目錄的輔助方法:

   /**
     *  構建目錄
     * @param outputDir 輸出目錄
     * @param subDir 子目錄
     */
    private static void createDirectory(String outputDir, String subDir){
        File file = new File(outputDir);
        if(!(subDir == null || subDir.trim().equals(""))) {//子目錄不為空
            file = new File(outputDir + File.separator + subDir);
        }
        if(!file.exists()){
            if(!file.getParentFile().exists()){
                file.getParentFile().mkdirs();
            }
            file.mkdirs();
        }
    }

 

tar文件解壓

接下來是正兒八經的正菜了。第一個來看怎么解壓tar文件。
好在解壓tar文件的工具JDK自帶了~下面看代碼:

    /**
     * 解壓縮tar文件
     * @param file 壓縮包文件
     * @param targetPath 目標文件夾
     * @param delete 解壓后是否刪除原壓縮包文件
     */
    private static void decompressTar(File file, String targetPath, boolean delete){
        FileInputStream fis = null;
        OutputStream fos = null;
        TarInputStream tarInputStream = null;
        try {
            fis = new FileInputStream(file);
            tarInputStream = new TarInputStream(fis, 1024 * 2);
            // 創建輸出目錄
            createDirectory(targetPath, null);

            TarEntry entry = null;
            while(true){
                entry = tarInputStream.getNextEntry();
                if( entry == null){
                    break;
                }
                if(entry.isDirectory()){
                    createDirectory(targetPath, entry.getName()); // 創建子目錄
                }else{
                    fos = new FileOutputStream(new File(targetPath + File.separator + entry.getName()));
                    int count;
                    byte data[] = new byte[2048];
                    while ((count = tarInputStream.read(data)) != -1) {
                        fos.write(data, 0, count);
                    }
                    fos.flush();
                }
            }
        } catch (IOException e) {
           e.printStackTrace();
        }finally {
            try {
                if(fis != null){
                    fis.close();
                }
                if(fos != null){
                    fos.close();
                }
                if(tarInputStream != null){
                    tarInputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

有一點需要注意的是:方法參數傳了一個是否需要刪除原壓縮包的參數,如果需要刪除的話,必須必須必須等到流關閉了之后才能刪除,不然是刪不掉的。也可以在該方法的調用者那里刪,這樣就可以不用傳這個參數了。

 

bz2文件解壓

解壓bz2文件我這里是用的Apache的commons.compress工具來解壓,先下載jar包:commons-compress-1.9.jar,(1.8的貌似有問題,我就換成了1.9)

    /**
     * 解壓縮bz2文件
     * @param file 壓縮包文件
     * @param targetPath 目標文件夾
     * @param delete 解壓后是否刪除原壓縮包文件
     */
    public static void decompressBZ2(File file, String targetPath, boolean delete){
        FileInputStream fis = null;
        OutputStream fos = null;
        BZip2CompressorInputStream bis = null;
        String suffix = ".bz2";
        try {
            fis = new FileInputStream(file);
            bis = new BZip2CompressorInputStream(fis);
            // 創建輸出目錄
            createDirectory(targetPath, null);
            File tempFile = new File(targetPath + File.separator + file.getName().replace(suffix, ""));
            fos = new FileOutputStream(tempFile);

            int count;
            byte data[] = new byte[2048];
            while ((count = bis.read(data)) != -1) {
                fos.write(data, 0, count);
            }
            fos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if(fis != null){
                    fis.close();
                }
                if(fos != null){
                    fos.close();
                }
                if(bis != null){
                    bis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

tar.bz2文件解壓

    /**
     * 解壓縮tar.bz2文件
     * @param file 壓縮包文件
     * @param targetPath 目標文件夾
     * @param delete 解壓后是否刪除原壓縮包文件
     */
    public static void decompressTarBz2(File file, String targetPath, boolean delete){
        FileInputStream fis = null;
        OutputStream fos = null;
        BZip2CompressorInputStream bis = null;
        TarInputStream tis = null;
        try {
            fis = new FileInputStream(file);
            bis = new BZip2CompressorInputStream(fis);
            tis = new TarInputStream(bis, 1024 * 2);
            // 創建輸出目錄
            createDirectory(targetPath, null);
            TarEntry entry;
            while((entry = tis.getNextEntry()) != null){
                if(entry.isDirectory()){
                    createDirectory(targetPath, entry.getName()); // 創建子目錄
                }else{
                    fos = new FileOutputStream(new File(targetPath + File.separator + entry.getName()));
                    int count;
                    byte data[] = new byte[2048];
                    while ((count = tis.read(data)) != -1) {
                        fos.write(data, 0, count);
                    }
                    fos.flush();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if(fis != null){
                    fis.close();
                }
                if(fos != null){
                    fos.close();
                }
                if(bis != null){
                    bis.close();
                }
                if(tis != null){
                    tis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

tar.gz文件解壓

    /**
     * 解壓縮tar.gz文件
     * @param file 壓縮包文件
     * @param targetPath 目標文件夾
     * @param delete 解壓后是否刪除原壓縮包文件
     */
    private static void decompressTarGz(File file, String targetPath,  boolean delete){
        FileInputStream  fileInputStream = null;
        BufferedInputStream bufferedInputStream = null;
        GZIPInputStream gzipIn = null;
        TarInputStream tarIn = null;
        OutputStream out = null;
        try {
            fileInputStream = new FileInputStream(file);
            bufferedInputStream = new BufferedInputStream(fileInputStream);
            gzipIn = new GZIPInputStream(bufferedInputStream);
            tarIn = new TarInputStream(gzipIn, 1024 * 2);

            // 創建輸出目錄
            createDirectory(targetPath, null);

            TarEntry entry = null;
            while((entry = tarIn.getNextEntry()) != null){
                if(entry.isDirectory()){ // 是目錄
                    createDirectory(targetPath, entry.getName()); // 創建子目錄
                }else{ // 是文件
                    File tempFIle = new File(targetPath + File.separator + entry.getName());
                    createDirectory(tempFIle.getParent() + File.separator, null);
                    out = new FileOutputStream(tempFIle);
                    int len =0;
                    byte[] b = new byte[2048];

                    while ((len = tarIn.read(b)) != -1){
                        out.write(b, 0, len);
                    }
                    out.flush();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if(out != null){
                    out.close();
                }
                if(tarIn != null){
                    tarIn.close();
                }
                if(gzipIn != null){
                    gzipIn.close();
                }
                if(bufferedInputStream != null){
                    bufferedInputStream.close();
                }
                if(fileInputStream != null){
                    fileInputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

gz文件解壓

    /**
     * 解壓縮gz文件
     * @param file 壓縮包文件
     * @param targetPath 目標文件夾
     * @param delete 解壓后是否刪除原壓縮包文件
     */
    private static void decompressGz(File file, String targetPath,  boolean delete){
        FileInputStream  fileInputStream = null;
        GZIPInputStream gzipIn = null;
        OutputStream out = null;
        String suffix = ".gz";
        try {
            fileInputStream = new FileInputStream(file);
            gzipIn = new GZIPInputStream(fileInputStream);
            // 創建輸出目錄
            createDirectory(targetPath, null);

            File tempFile = new File(targetPath + File.separator + file.getName().replace(suffix, ""));
            out = new FileOutputStream(tempFile);
            int count;
            byte data[] = new byte[2048];
            while ((count = gzipIn.read(data)) != -1) {
                out.write(data, 0, count);
            }
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if(out != null){
                    out.close();
                }
                if(gzipIn != null){
                    gzipIn.close();
                }
                if(fileInputStream != null){
                    fileInputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

7z文件解壓

    /**
     * 解壓縮7z文件
     * @param file 壓縮包文件
     * @param targetPath 目標文件夾
     * @param delete 解壓后是否刪除原壓縮包文件
     */
    private static void decompress7Z(File file, String targetPath,  boolean delete){
        SevenZFile sevenZFile = null;
        OutputStream outputStream = null;
        try {
            sevenZFile = new SevenZFile(file);
            // 創建輸出目錄
            createDirectory(targetPath, null);
            SevenZArchiveEntry entry;

            while((entry = sevenZFile.getNextEntry()) != null){
                if(entry.isDirectory()){
                    createDirectory(targetPath, entry.getName()); // 創建子目錄
                }else{
                    outputStream = new FileOutputStream(new File(targetPath + File.separator + entry.getName()));
                    int len = 0;
                    byte[] b = new byte[2048];
                    while((len = sevenZFile.read(b)) != -1){
                        outputStream.write(b, 0, len);
                    }
                    outputStream.flush();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if(sevenZFile != null){
                    sevenZFile.close();
                }
                if(outputStream != null){
                    outputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

rar文件解壓

先下載jar包:junrar-0.7.jar、xz-1.5.jar、commons-logging.jar

/**
     * 解壓縮RAR文件
     * @param file 壓縮包文件
     * @param targetPath 目標文件夾
     * @param delete 解壓后是否刪除原壓縮包文件
     */
    private static void decompressRAR(File file, String targetPath,  boolean delete){
        Archive archive = null;
        OutputStream outputStream = null;
        try {
            archive = new Archive(file);
            FileHeader fileHeader;
            // 創建輸出目錄
            createDirectory(targetPath, null);
            while( (fileHeader = archive.nextFileHeader()) != null){
                if(fileHeader.isDirectory()){
                    createDirectory(targetPath, fileHeader.getFileNameString().trim()); // 創建子目錄
                }else{
                    outputStream = new FileOutputStream(new File(targetPath + File.separator + fileHeader.getFileNameString().trim()));
                    archive.extractFile(fileHeader, outputStream);
                }
            }
        } catch (RarException | IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if(archive != null){
                    archive.close();
                }
                if(outputStream != null){
                    outputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM