【问题标题】:Compress up to 24mb files into .zip using ZipOutputStream in Android在 Android 中使用 ZipOutputStream 将最多 24mb 的文件压缩为 .zip
【发布时间】:2016-02-25 22:06:03
【问题描述】:

我正在尝试将目录从一个区域(sdCard/someFolder) 压缩到第二个目录(sdCard/Download),直到 .zip 文件大小变为 5mb。然后,我想创建一个新的.zip 文件,将新的文件填充到 5mb 等。

目前,我的代码成功地将文件压缩到 .zip 目录中,但 .zip 目录之一总是损坏。当我的 for 循环退出 22 objects 的第一个 Files[] 并以 Files[]4 objects 开始下一个目录时,我看到了这一点。我相信我正在失去对旧 OutputStreams 的一些清理。在第二次尝试 for 循环后,out.putNextEntry() 变为 null。任何帮助都足够了。

private static void addDirToArchive(ZipOutputStream out, FileOutputStream destinationDir, File sdCardMNDLogs)
{
    File[] listOfFiles = sdCardMNDLogs.listFiles();

    BufferedInputStream origin = null;

    Log.i(TAG3, "Reading directory: " + sdCardMNDLogs.getName());

    try{

    byte[] buffer = new byte[BUFFER];
    for(int i = 0; i < listOfFiles.length; i++)
    {
        if(listOfFiles[i].isDirectory())
        {
            addDirToArchive(out, destinationDir, listOfFiles[i]);
            continue;
        }
        try 
        {
            FileInputStream fis = new FileInputStream(listOfFiles[i]);
            origin = new BufferedInputStream(fis,BUFFER);
            ZipEntry ze = new ZipEntry(listOfFiles[i].getName());

            if(currentZipFileSize >= EMAIL_SIZE)
            {
                out.close();
                Log.d(emailTAG, "Creating new zipfile: /Download/MND/nwdLogs_" + i);
                out = new ZipOutputStream(new FileOutputStream(new File(sdCard.getAbsolutePath() + "/Download/MND/nwdLogs_ " + i + ".zip")));
                currentZipFileSize = 0;
            }
            out.putNextEntry(ze);
            int length;
            Log.i(TAG3, "Adding file: " + listOfFiles[i].getName());
            while((length = origin.read(buffer, 0, BUFFER)) != -1)
            {
                out.write(buffer, 0, length);
            }
            out.closeEntry();
            origin.close();
            currentZipFileSize = currentZipFileSize + ze.getCompressedSize();
        }
        catch(IOException ioe)
        {
            Log.e(TAG3, "IOException: " + ioe);
        }
    }
    }
    finally
    {
        try {
            out.close();
    } catch (IOException e) 
    {
        e.printStackTrace();
    }
}

}

FileOutputStream destinationDir = new FileOutputStream(sdCard.getAbsolutePath() + "/Download/Dir/nwdLogs.zip");
ZipOutputStream out = new ZipOutputStream(destinationDir);

currentZipFileSize = 0;
addDirToArchive(out, destinationDir, dirName);
out.close();
destinationDir.close();

【问题讨论】:

    标签: java android zipoutputstream


    【解决方案1】:

    我怀疑问题在于您在打开下一个 ZIP 文件之前没有调用 out.close()。我的理解是 ZIP 的索引仅在 ZIP 关闭时写入,因此如果您忽略关闭索引将丢失:因此损坏。

    另外,请注意您不需要同时关闭 fisorigin。只需关闭origin ...它就会关闭fis


    更新 - 虽然您已经修复了最初的关闭错误,但还有更多:

    1. 您已添加 finally 块以关闭 out。那是错的。您不希望 addDirToArchive 关闭 out。这可能是您的异常的原因。

    2. 完成此操作后会出现几个问题:

      if (currentZipFileSize >= EMAIL_SIZE)
          {
              out.close();
              out = new ZipOutputStream(new FileOutputStream(...));
              currentZipFileSize = 0;
          }
      

      由于out是本地参数,调用者看不到变化 你做。因此:

      • 当您在调用者中调用 out.close() 时,您可能正在关闭 原来的 ZIP(已经关闭)...不是当前的

      • 如果你打电话给addDirToArchive(out, destinationDir, dirName) 多次,在随后的调用中,您可能会传递一个封闭的 ZIP 文件。

    3. 您的异常处理被误导了 (IMO)。如果将文件写入 ZIP 时出现 I/O 错误,您不希望记录消息并继续操作。你想保释。要么完全崩溃应用程序,要么停止做你正在做的事情。在这种情况下,您的“流已关闭”显然是代码中的一个错误,而您的异常处理实际上是在告诉应用忽略它。

    一些建议:

    • 如果您将打开和关闭资源的责任分散到多个方法中,您需要非常小心哪些代码负责关闭哪些内容。你需要了解你在做什么。

    • 盲目地应用(所谓的)“解决方案”(如finally 的东西)......因为有人说“XXX 是最佳实践”或“总是做 XXX”......会让你陷入麻烦。您需要 1) 了解“解决方案”的作用,以及 2)思考该解决方案是否真正满足您的需求。

    【讨论】:

    • 我在创建新的 ZipOutputStream 之前和对 addDirToArchive(out,destinationDir, dirName) 的初始调用之后缺少一个 out.close()。谢谢。
    • 现在我遇到的问题是包含两个文件夹和两个文件的原始目录将无法正确读取。由于错误,程序将压缩 File[] 中的第一个目录,但不会压缩其他三个目录:Stream is closed.
    猜你喜欢
    • 2017-08-16
    • 2020-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多