【问题标题】:ZipOutputStream produces corrupted zip file on AndroidZipOutputStream 在 Android 上生成损坏的 zip 文件
【发布时间】:2014-08-31 18:05:58
【问题描述】:

我已经使用 zip 存档从应用程序备份用户数据,我正在将数据库和共享首选项文件复制到 zip 存档并计算输入文件的 MD5 校验和以防止用户修改备份数据。

要从存档中恢复,我将备份文件解压缩到临时目录,检查校验和,然后将首选项\数据库文件复制到相应的文件夹中。

我的一些用户抱怨应用程序生成损坏的备份文件(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);
    }
}

【问题讨论】:

  • 我猜你应该在关闭流之前调用stream.flush();
  • 我添加了 stream.flush();在 stream.finish() 之后 - 有时仍会收到损坏的 zip 文件。
  • 是否有可能获取此类损坏的 zip 文件的示例?

标签: java android zipfile


【解决方案1】:

您可以考虑使用 zip4j 库。我通过使用这个库解决了我遇到的问题(相同的问题 - 不同的方向)。一些 zip 文件无法使用原生 android 实现解码,但使用 zip4j。您也可以通过使用 zip4j 进行压缩来解决您的问题。

【讨论】:

  • 谢谢,我试试看
【解决方案2】:

这里有一些代码仅使用 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();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-25
    • 1970-01-01
    相关资源
    最近更新 更多