2

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

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

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

1 回答 1

2

我怀疑问题在于您out.close()在打开下一个 ZIP 文件之前没有打电话。我的理解是 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)考虑该解决方案是否真正满足您的需求。

于 2016-02-25T22:49:00.130 回答