2014-08-31 1 views
3

Zip 아카이브를 사용하는 앱에서 사용자 데이터의 백업을 구현했습니다. 데이터베이스 및 공유 환경 설정 파일을 Zip 아카이브로 복사하고 사용자가 백업 데이터를 수정하지 못하도록 입력 파일의 MD5 체크섬을 계산합니다. .ZipOutputStream이 Android에서 손상된 zip 파일을 생성합니다.

아카이브에서 복원하려면 백업 파일을 임시 디렉토리에 압축을 해제하고 체크섬을 선택한 다음 해당 폴더에 환경 설정 \ 데이터베이스 파일을 복사하십시오.

일부 사용자는 앱이 손상된 백업 파일을 생성한다고 불평하고 있습니다 (zip 파일이 실제로 손상됨).

public void backup(String filename) { 
    File file = new File(getBackupDirectory(), filename); 
    FileOutputStream fileOutputStream = null; 
    ZipOutputStream stream = null; 
    try { 
     String settingsMD5 = null; 
     String databaseMD5 = null; 
     if (file.exists()) 
      file.delete(); 
     fileOutputStream = new FileOutputStream(file); 
     stream = new ZipOutputStream(new BufferedOutputStream(fileOutputStream)); 
     File database = getDatabasePath(databaseFileName); 
     File dataDirectory = getFilesDir(); 
     if (dataDirectory != null) { 
      File settings = new File(dataDirectory.getParentFile(), "/shared_prefs/" + PREFERENCES_FILENAME); 
      settingsMD5 = zipFile("preferences", stream, settings); 
     } 
     databaseMD5 = zipFile("database.db", stream, database); 

     JSONObject jsonObject = new JSONObject(); 
     try { 
      jsonObject.put(META_DATE, new SimpleDateFormat(DATE_FORMAT, Locale.US).format(new Date())); 
      jsonObject.put(META_DATABASE, databaseMD5); 
      jsonObject.put(META_SHARED_PREFS, settingsMD5); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     InputStream metadata = new ByteArrayInputStream(jsonObject.toString().getBytes("UTF-8")); 
     zipInputStream(stream, metadata, new ZipEntry("metadata")); 
     stream.finish(); 
     stream.close(); 
     stream = null; 
     return file; 
    } catch (FileNotFoundException e) { 
    //handling errrors 
    } catch (IOException e) { 
    //handling errrors 
    } 
} 

private String zipFile(String name, ZipOutputStream zipStream, File file) throws FileNotFoundException, IOException { 
     ZipEntry zipEntry = new ZipEntry(name); 
     return zipInputStream(zipStream, new FileInputStream(file), zipEntry); 
    } 

private String zipInputStream(ZipOutputStream zipStream, InputStream fileInputStream, ZipEntry zipEntry) throws IOException { 
    InputStream inputStream = new BufferedInputStream(fileInputStream); 
    MessageDigest messageDigest = null; 
    try { 
     messageDigest = MessageDigest.getInstance("MD5"); 
     if (messageDigest != null) 
      inputStream = new DigestInputStream(inputStream, messageDigest); 
    } catch (NoSuchAlgorithmException e) { 
    } 

    zipStream.putNextEntry(zipEntry); 
    inputToOutput(inputStream, zipStream); 
    zipStream.closeEntry(); 
    inputStream.close(); 

    if (messageDigest != null) { 
     return getDigestString(messageDigest.digest()); 
    } 
    return null; 
} 

private String getDigestString(byte[] digest) { 
    StringBuffer hexString = new StringBuffer(); 
    for (int i = 0; i < digest.length; i++) { 
     String hex = Integer.toHexString(0xFF & digest[i]); 
     if (hex.length() == 1) { 
      hex = new StringBuilder("0").append(hex).toString(); 
     } 
     hexString.append(hex); 
    } 
    return hexString.toString(); 
} 

private void inputToOutput(InputStream inputStream, OutputStream outputStream) throws IOException { 
    byte[] buffer = new byte[BUFFER]; 
    int count = 0; 
    while ((count = inputStream.read(buffer, 0, BUFFER)) != -1) { 
     outputStream.write(buffer, 0, count); 
    } 
} 
+0

난 당신이)'를 호출 stream.flush (해야 추측; 스트림을 닫기 전에'. – SubOptimal

+0

stream.flush()를 추가했습니다. stream.finish() 이후 - 가끔 손상된 zip 파일을받는 경우가 있습니다. – nemezis

+0

손상된 zip 파일의 예가 될 수 있습니까? – SubOptimal

답변

2

당신은 zip4j lib 디렉토리를 사용하는 것이 좋습니다 : 여기

은 zip 파일에 대한 모든 파일을 압축 코드입니다. 나는이 lib를 사용하여 내가 가진 문제 (같은 문제 - 다른 방향)를 해결했다. 일부 zip 파일은 원시 안드로이드 구현으로 디코딩 할 수 없지만 zip4j는 사용할 수 없습니다. 압축을 위해 zip4j를 사용하여 문제를 해결할 수도 있습니다.

+0

감사합니다. 시험해 보겠습니다. – nemezis

1

다음은 Java 표준 클래스 만 사용하여 디렉토리를 파일로 압축하는 코드입니다. 이것으로 당신은 단지 호출 할 수

ZipUtils.zip(sourceDirectory, targetFile); 
ZipUtils.unzip(sourceFile, targetDirectory); 

코드 :

package com.my.project.utils.zip; 

import java.io.IOException; 
import java.nio.file.FileVisitResult; 
import java.nio.file.Files; 
import java.nio.file.Path; 
import java.nio.file.SimpleFileVisitor; 
import java.nio.file.attribute.BasicFileAttributes; 
import java.util.zip.ZipEntry; 
import java.util.zip.ZipOutputStream; 

public class ZipUtils { 

    public static void unzip(Path sourceFile, Path targetPath) throws IOException { 
     try (ZipInputStream zipInStream = new ZipInputStream(Files.newInputStream(sourceFile))){ 
      byte[] buffer = new byte[1024]; 
      Files.createDirectories(targetPath); 

      ZipEntry entry = null; 

      while ((entry = zipInStream.getNextEntry()) != null){ 
       Path entryPath = targetPath.resolve(entry.getName()); 
       Files.createDirectories(entryPath.getParent()); 
       Files.copy(zipInStream, entryPath); 
       zipInStream.closeEntry(); 
      } 
     } 
    } 

    public static void zip(Path sourcePath, Path targetFile) throws IOException { 
     try (ZipOutputStream zipOutStream = new ZipOutputStream(Files.newOutputStream(targetFile))){ 
      if (Files.isDirectory(sourcePath)){ 
       zipDirectory(zipOutStream, sourcePath); 
      } else { 
       createZipEntry(zipOutStream, sourcePath, sourcePath); 
      } 
     } 
    } 

    private static void zipDirectory(ZipOutputStream zip, Path source) throws IOException { 
     Files.walkFileTree(source, new SimpleFileVisitor<Path>(){ 
      @Override 
      public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { 
       return FileVisitResult.CONTINUE; 
      }   
      @Override 
      public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException { 
       createZipEntry(zip, source, path); 
       return FileVisitResult.CONTINUE; 
      } 
     }); 
    }  

    private static void createZipEntry(ZipOutputStream zip, Path sourcePath, Path path) throws IOException { 
     ZipEntry entry = new ZipEntry(sourcePath.relativize(path).toString()); 
     zip.putNextEntry(entry); 
     Files.copy(path,zip); 
     zip.closeEntry(); 
    } 
} 
관련 문제