스마트기기개발관련/안드로이드 개발

android에서 zip 파일 압축 해제(unzip)

AlrepondTech 2014. 4. 18. 15:53
반응형

 

 

 

 

 

=======================

=======================

=======================

 

 

 

 

 

출처: http://blog.naver.com/PostView.nhn?blogId=mindori17&logNo=120196766106

 

안드로이드 어플 내에서 어플의 res나 다른 폴더에 있는 zip 파일의 압축을 다른 폴더로 푸는 방식에 대해서  

 

제가 구글링을 통해 알게 된 내용을 말씀드리겠습니다.

 

 

먼저 참조한 곳은 아래와 같습니다.  

 

설명이 매우 쉽게 되어 있어서 보시면 금방 동작 원리를 알 수 있으실 것 같습니다.

 

http://www.jondev.net/articles/Unzipping_Files_with_Android_%28Programmatically%29

 

 

저는 두 가지 경우에 대하여 말씀드리겠는데요. 

 

zip 파일이 phone 내부의 폴더 내에 있을 때와 해당 application의 res 안에 있을 경우 입니다.

 

 

1) 해당 zip파일이 phone의 내부 폴더에 있을 때

 

먼저 Decompress 라는 class를 아래와 같이 선언 합니다.

 

****************************

import android.util.Log; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.util.zip.ZipEntry; 
import java.util.zip.ZipInputStream; 
 


public class Decompress { 
  private String _zipFile;  //저장된 zip 파일 위치
  private String _location; //압출을 풀 위치
 
  public Decompress(String zipFile, String location) { 
    _zipFile = zipFile; 
    _location = location; 
 
    _dirChecker("")//폴더를 만들기 위한 함수로 아래에 정의 되어 있습니다.
  } 
 
  public void unzip() { 
    try  { 
      FileInputStream fin = new FileInputStream(_zipFile)
      ZipInputStream zin = new ZipInputStream(fin)
      ZipEntry ze = null
      while ((ze = zin.getNextEntry()) != null) { 
        Log.v("Decompress""Unzipping " + ze.getName());   //압축이 풀리면서 logcat으로 zip 안에 있던 파일        if(ze.isDirectory()) {                                  들을 볼 수 있습니다.

          _dirChecker(ze.getName())
        } else { 
                   FileOutputStream fout = new FileOutputStream(_location + ze.getName())
                    BufferedInputStream in = new BufferedInputStream(zin);  //이렇게 지정하지 않고 unzip을
                    BufferedOutputStream out = new BufferedOutputStream(fout)수행하면 속도가 매우 느려
                    byte b[] = new byte[1024];                                  집니다.
                    int n;
                    while ((n = in.read(b,0,1024)) >= 0) {
                      out.write(b,0,n);
                    }
    
                  zin.closeEntry()
                  fout.close();
        } 
         
      } 
      zin.close()
    } catch(Exception e) { 
      Log.e("Decompress""unzip", e)
    } 
 
  } 
 

//변수 location에 저장된 directory의 폴더를 만듭니다.
  private void _dirChecker(String dir) { 
    File f = new File(_location + dir)
 
    if(!f.isDirectory()) {   
      f.mkdirs();  
    } 
  } 
}

********************************************

 

이제 압축 풀기를 실행하고 싶은 부분에 다음과 같은 코드를 삽입하여 정의한 class를 실행하여 unzip을 수행합니다.

 

zipFile과 unzipLocation만 각자 상황에 맞게 수정하시면 될 것 같습니다.

 

 

 

 1)-1 외부 메모리에 압축 해제 (rooting을 하지 않아도 폴더를 볼 수 있음)

 

***********************************************************************************************

String zipFile = Environment.getExternalStorageDirectory() + "/files.zip";  //zip 파일이 있는 위치 정의
String unzipLocation = Environment.getExternalStorageDirectory() + "/unzipped/";  //unzip 하고자 하는 위치
 
Decompress d = new Decompress(zipFile, unzipLocation)
d.unzip();

***********************************************************************************************

 

 

 

반응형

 

 

728x90

 

 

 1)-2 해당 application의 폴더 내에 압축 해제 (rooting을 하지 않으면 폴더에 접근할 수 없지만 해당 application 안에서는 접근 가능)

 

일단적으로 application은 smart phone 내부의 /data/app/ 의 경로에 설치 되는 데요.

 

이 /data안의 내용은 rooting을 하지 않으면 볼 수 없습니다. (탐색시 빈 폴더로 표기 됩니다.)

 

또한 다른 application에서 보안상의 이유로 접근을 할 수 도 없습니다.

 

그러나 해당 application으로는 접근과 사용이 가능하기 때문에 현재 동작하는 application에서 자신의 폴더 안에 unzip이 가능합니다.

 

그 방법은 위와 동일하며 지금 실행되는 application의 설치 위치를 얻기 위한 부분과 예외 처리 부분만 달라집니다.

 

먼저 unzip을 수행하고자 하는 부분에 아래와 같은 코드를 삽입하여 unzip을 수행합니다.

 

***********************************************************************************************

  String apploc=Environment.getExternalStorageDirectory()+"/"//우선 path를 외부 메모리의 path로 설정
        try {
            apploc=getDataDir()+"/";   //현재 실행되는 app의 설치 경로를 얻음
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        String unzipLocation =  apploc+ "unzipped/";  //현재 실행되는 app 내부의 unzipped라는 폴더로 
        Decompress d = new Decompress(unzipLocation);    설치경로 지정   
        d.unzip();  //unzip 수행
        
        String fulldir=apploc+ "unzipped";   //이후엔 unzip이 제대로 수행했는지 확인하기 위하여 unziped폴더
        File fileList = new File(fulldir);      안의 파일 이름을 log cat에 출력
         File[] filenames = fileList.listFiles();
         for (File tmpf : filenames){
             Log.d("Existing File :",fulldir+"/"+tmpf.getName() );  

***********************************************************************************************

 

위에서 사용한 getDataDir()은 아래와 같이 정의 해 줍니다.

 

***********************************************************************************************

public String getDataDir() throws Exception 
    { Log.d("*****************", getApplicationContext().getPackageManager().getPackageInfo(getPackageName()0).applicationInfo.dataDir)
        return getApplicationContext().getPackageManager().getPackageInfo(getPackageName()0).applicationInfo.dataDir;
    }

***********************************************************************************************

 

 

 

2) zip파일이 해당 application의 res 폴더 안에 있을 때

 

소스가 거의 동일해서 또 올리기 민망하지만 긁어 붙이기의 편의를 위해 올리겠습니다.

 

zip 파일은 다음 그림과 같이 res/raw에 있을 때의 경우 입니다.

 

 

 

 

 

****************************

import android.util.Log; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.util.zip.ZipEntry; 
import java.util.zip.ZipInputStream; 
 
public class Decompress { 
  private String _location; //압출을 풀 위치
 
  public Decompress(String location) { 
    _location = location; 
 
    _dirChecker("")//폴더를 만들기 위한 함수로 아래에 정의 되어 있습니다.
  } 
 
  public void unzip() { 
    try  { 
final ZipInputStream zin = new ZipInputStream(getResources().openRawResource(R.raw.haa));

 

//이 부분을 바꿔어 주셔야 합니다. 저의 경우 zip 파일이 res/raw 폴더 안의 haa.zip 이었습니다. 

 

      ZipEntry ze = null
      while ((ze = zin.getNextEntry()) != null) { 
        Log.v("Decompress""Unzipping " + ze.getName());   //압축이 풀리면서 logcat으로 zip 안에 있던 파일        if(ze.isDirectory()) {                                  들을 볼 수 있습니다.

          _dirChecker(ze.getName())
        } else { 
                   FileOutputStream fout = new FileOutputStream(_location + ze.getName())
                    BufferedInputStream in = new BufferedInputStream(zin);
                    BufferedOutputStream out = new BufferedOutputStream(fout);      
                    byte b[] = new byte[1024];
                    int n;
                    while ((n = in.read(b,0,1024)) >= 0) {
                      out.write(b,0,n);
                    }
             
                  zin.closeEntry()
                  fout.close();
        } 
         
      } 
      zin.close()
    } catch(Exception e) { 
      Log.e("Decompress""unzip", e)
    } 
 
  } 
 

//변수 location에 저장된 directory의 폴더를 만듭니다.
  private void _dirChecker(String dir) { 
    File f = new File(_location + dir)
 
    if(!f.isDirectory()) {   
      f.mkdirs();  
    } 
  } 
}

********************************************

 

이제 unzip 수행을 명령하고 싶은 곳에 다음과 같이 정의한 class를 실행 시켜 줍니다.

 

위와 다른 점은 Decompress 안에서 대상이 되는 zip 파일 위치를 정의 하였기 때문에 압축을 풀 곳만 지정해 주시면 됩니다.

 

***********************************************************************************************

String unzipLocation = Environment.getExternalStorageDirectory() + "/unzipped/";  //unzip 하고자 하는 위치
 
Decompress d = new Decompress(unzipLocation)
d.unzip();

***********************************************************************************************

 
 
 
막상 작성해 보니 Decompress를 다르게 두개로 할 것이 아니라 String _zipFile이 directory인지 res안의 파일인지를
 
보고 _zipFile 변수에 맞게 unzip을 수행하는 class로 만들면 한번 class를 정의해 놓고 
 
범용적으로 사용이 가능 할 것 같다는 생각이 듭니다.
 
 
이번 글에서는 단지 1)과 같은 일반적인 코드에서 2)와 같이 바꾸면 res안의 zip 파일도 unzip 할 수 있다는 것을 
 
보여드리고 싶었습니다.

 

 

 

 

=======================

=======================

=======================

 

 

 

출처: https://blog.naver.com/llloveshin/221550313475

 

여기 나와있는 소스대로 사용하면 압축이 잘 풀리지만, 중간에 outputStream이 flush 되지 않아 파일이 잘리는 현상이 있다.

같은 내용의 소스가 국내외 많은 사이트에서 소개되고 있기 때문에, 다른 부분에서 문제가 있는줄 알고 한참을 삽질했다.

BufferedOutputStream out = new BufferedOutputStream(fout);

이녀석이 flush 되지 않고 있다.

out.close(); <- 이 한줄을 추가하니 문제없이 unzip된다.

zin.closeEntry();

fout.close();

참고로 위 링크에 있는 소스는 byte 단위로 처리하기 때문에, 파일명이 한글인 경우 정상적으로 압축이 풀리지 않는다.

따라서 char 단위로 처리하는 reader 클래스를 사용하는 소스로 바꾸거나, 파일명에 한글이 없도록 해야 한다.

 

[출처] Android Studio Unzip|작성자 셀이다

 

 

=======================

=======================

=======================

 

 

 

반응형