2014-08-31 131 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 2014-10-21 06:39:22

+0

我已添加stream.flush(); stream.finish()之後 - 有時仍然收到損壞的zip文件。 – nemezis 2014-10-21 06:42:05

+0

是否有可能成爲這種損壞的zip文件的例子? – SubOptimal 2014-10-21 09:44:11

回答

2

你可能會考慮使用zip4j庫。我通過使用這個lib解決了我的問題(同樣的問題 - 不同的方向)。一些zip文件不能用本機android實現進行解碼,但使用zip4j。您也可以通過使用zip4j進行壓縮來解決您的問題。

+0

謝謝,我會試一試 – nemezis 2014-10-18 20:46:07

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(); 
    } 
}