【Android】Android開發文件壓縮與解壓

壓縮文件或目錄

 public static void zip(String src,String dest) throws IOException {
        //定義壓縮輸出流
        ZipOutputStream out = null;
        try {
            //傳入源文件
            File fileOrDirectory= new File(src);
            File outFile= new File(dest);
            //傳入壓縮輸出流
            //創建文件前幾級目錄
            if (!outFile.exists()){
                File parentfile=outFile.getParentFile();
                if (!parentfile.exists()){
                    parentfile.mkdirs();
                }
            }
            //可以通過createNewFile()函數這樣創建一個空的文件,也可以通過文件流的使用創建
            out = new ZipOutputStream(new FileOutputStream(outFile));
            //判斷是否是一個文件或目錄
            //如果是文件則壓縮
            if (fileOrDirectory.isFile()){
                zipFileOrDirectory(out,fileOrDirectory, "");
            } else {
                //否則列出目錄中的所有文件遞歸進行壓縮

                File[]entries = fileOrDirectory.listFiles();
                for (int i= 0; i < entries.length;i++) {
                    zipFileOrDirectory(out,entries[i],fileOrDirectory.getName()+"/");//傳入最外層目錄名

                }
            }
        }catch(IOException ex) {
            ex.printStackTrace();
        }finally{
            if (out!= null){
                try {
                    out.close();
                }catch(IOException ex) {
                    ex.printStackTrace();
                }
            }
        }
    }

    private static void zipFileOrDirectory(ZipOutputStream out, File fileOrDirectory, String curPath)throws IOException {
        FileInputStream in = null;
        try {
            //判斷是否爲目錄
            if (!fileOrDirectory.isDirectory()){
                byte[] buffer= new byte[4096];
                int bytes_read;
                in= new FileInputStream(fileOrDirectory);//讀目錄中的子項
                //歸檔壓縮目錄
                ZipEntry entry = new ZipEntry(curPath + fileOrDirectory.getName());//壓縮到壓縮目錄中的文件名字
                //getName() 方法返回的路徑名的名稱序列的最後一個名字,這意味着表示此抽象路徑名的文件或目錄的名稱被返回。
                //將壓縮目錄寫到輸出流中
                out.putNextEntry(entry);//out是帶有最初傳進的文件信息,一直添加子項歸檔目錄信息
                while ((bytes_read= in.read(buffer))!= -1) {
                    out.write(buffer,0, bytes_read);
                }
                out.closeEntry();
            } else {
                //列出目錄中的所有文件
                File[]entries = fileOrDirectory.listFiles();
                for (int i= 0; i < entries.length;i++) {
                    //遞歸壓縮
                    zipFileOrDirectory(out,entries[i],curPath + fileOrDirectory.getName()+ "/");//第一次傳入的curPath是空字符串
                }//目錄沒有後綴所以直接可以加"/"
            }
        }catch(IOException ex) {
            ex.printStackTrace();
        }finally{
            if (in!= null){
                try {
                    in.close();
                }catch(IOException ex) {
                    ex.printStackTrace();
                }
            }
        }
    }

思路:
1.創建文件壓縮輸出流ZipOutputStream ,和文件讀入流FileInputStream
2.Zipoutputstream綁定一個目標目錄,用ZipEntry歸檔在目標目錄中添加輸出子項
ZipEntry entry = new ZipEntry(curPath + fileOrDirectory.getName());
out.putNextEntry(entry);
3.FileInputStream在每次讀入時綁定需要讀入的文件
壓縮時putNextEntry()對應解壓時的getNextEntry()

解壓文件或目錄##

 public static void UnZipFolder(String FILE_PATH, String outPath) throws Exception{
        File zipFile = new File(FILE_PATH);//FILE_PATH爲壓縮文件的路徑
        ZipFile zf = new ZipFile(zipFile);
        for(Enumeration<?> entries = zf.entries(); entries.hasMoreElements();){//遍歷壓縮文件中的所有歸檔過的文件

            ZipEntry entry = ((ZipEntry)entries.nextElement());//默認爲-1,next->下標0的位置
            InputStream is = zf.getInputStream(entry);
            String str = outPath + File.separator + entry.getName();
            str = new String(str.getBytes("8859_1"),"GB2312");//壓縮文件的編碼是8859_1,此處可將其轉換成指定的編碼
            File desFile = new File(str);//其中單執行new file並不會在存儲中創建文件或文件夾
            if(!desFile.exists()){
                File fileParentDir = desFile.getParentFile();
                if(!fileParentDir.exists()){
                    fileParentDir.mkdirs();//多級目錄同時創建  怕文件歸檔在很多級目錄下,或者文件需要在很多級未創建目錄下,mkdir不會創建父目錄,mkdirs會
                }
                desFile.createNewFile();//如果沒有父目錄將創建失敗
            }
            FileOutputStream out = new FileOutputStream(desFile);
            byte buffer[] = new byte[1024*1024];
            int readLength;
            while((readLength = is.read(buffer)) > 0){
                out.write(buffer, 0, readLength);
            }
            is.close();
            out.close();
        }
    }

思路:
1.創建ZipFile對象
2.通過entry找到對應壓縮文件輸入流
InputStream is = zf.getInputStream(entry);
3.輸入輸出

爲了解決有時我們需要從解壓完的目錄中獲得某個指定文件的要求

/*
* 搜索對應文件從某目錄中
* */
//保存搜索到的文件
    static File file;
    public static File findFile(File fileorfolder,String requestFile){
        file=null;//重置標識搜索文件的file爲空
        searchFile(fileorfolder,requestFile);
        return file;
    }
    private static void searchFile(File fileorfolder,String requestFile){
        //是目錄
        if(fileorfolder.isDirectory()){

            File[] entries=fileorfolder.listFiles();
            for(File enrtyfile:entries){
                searchFile(enrtyfile,requestFile);
            }
            //是文件
        }else {
            //是傳入文件名對應文件
            if (fileorfolder.getName().equals(requestFile)){//equals是比較字符串值是否相等
                file=fileorfolder;
            }
        }
    }

##踩過的坑

1.壓縮目錄後解壓,最外層目錄丟失 例:/360/3/1(目錄)2(目錄) 壓縮解壓完/360消失,只剩/3 解決:歸檔代碼出錯,沒有把歸檔信息帶上最外層目錄
2.(No such file or directory)異常,輸出時在new file的file路徑不存在(存在多級未創建目錄) 解決:
(1).desFile.createNewFile();
(2).FileOutputStream out = new FileOutputStream(desFile);
(1).(2)兩種方法都會創建文件,但如果沒有父目錄將創建失敗,父目錄可通過mkdirs創建,將遞歸創建
if (!outFile.exists()){
File parentfile=outFile.getParentFile();
if (!parentfile.exists()){
parentfile.mkdirs();
} }

使用到的一些類

ZipOutputStream :DeflaterOutputStream的一個子類,把數據壓縮成Zip文件格式。
  ZipInputStream :InflaterInputStream的一個子類,能解壓縮Zip格式的數據
  ZipEntry 類:表示 ZIP 文件條目
  ZipFile 類:此類用於從 ZIP 文件讀取條目

ps:

1.壓縮時的ZipEntry 非常重要,是解壓時取得的歸檔信息
2.文件夾就算改成有後綴並不影響是文件夾:example->example.jpg還是文件夾
3.可以通過createNewFile()函數這樣創建一個空的文件,也可以通過文件流的使用創建
desFile.createNewFile();//如果沒有父目錄將創建失敗
FileOutputStream out = new FileOutputStream(desFile);//如果沒有父目錄將創建失敗,即No such file or directory

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章