2

.zip ファイルのサイズが 5 MB になるまで、ディレクトリを 1 つの領域から(sdCard/someFolder)2 番目のディレクトリに圧縮しようとしています。(sdCard/Download)次に、新しいファイルを作成し、その新しい.zipファイルを最大5MBまで埋めたい.

現在、私のコードはファイルを .zip ディレクトリに正常に圧縮しますが、.zip ディレクトリの 1 つが常に破損します。for ループが最初Files[]の ofを終了し、 of22 objectsで次のディレクトリを開始すると、これが表示されます。古い OutputStreams のクリーンアップが失われていると思います。for ループの2 回目の試行の後、 は 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 が閉じられたときにのみ書き込まれるため、閉じないとインデックスが失われ、破損します。

fisまた、 と の両方を閉じる必要はないことに注意してくださいorigin。閉じるだけ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 (既に閉じられている) が閉じられている可能性があります...現在の ZIP ではありません

    • 複数回呼び出すaddDirToArchive(out, destinationDir, dirName) と、その後の呼び出しで閉じた ZIP ファイルを渡す可能性があります。

  3. あなたの例外処理は見当違いです (IMO)。ファイルを ZIP に書き込むときに I/O エラーが発生した場合、メッセージをログに記録して続行する必要はありません。あなたは救済したい。アプリを完全にクラッシュさせるか、やっていることをやめてください。この場合、「ストリームが閉じられている」ことは明らかにコードのバグであり、例外処理はアプリにそれを無視するよう効果的に伝えています。

いくつかのアドバイス:

  • リソースのオープンとクローズの責任を複数のメソッドに分割している場合は、どのコードが何をクローズする責任があるかについて非常に注意する必要があります。自分が何をしているのかを理解する必要があります。

  • (いわゆる)「解決策」(ものなど)を盲目的に適用するfinally...「誰かが「XXXはベストプラクティス」または「常にXXXを行う」と言うので...あなたを困らせるでしょう. 1) 「ソリューション」が何をするかを理解し、2)ソリューションが実際に必要な機能を果たしているかどうかを考える必要があります。

于 2016-02-25T22:49:00.130 に答える