3

フォルダーからzipファイルのリストを抽出し、パスワードで再圧縮しようとしています。問題は、再圧縮中に反復/ループが停止しないことです。また、再圧縮されたファイルは、すべてのコンテンツを 1 つの zip にマージするのではなく、それぞれ別の zip ファイルにする必要があります。

これが私が試したことです:

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;

public class AddFilesWithAESEncryption2 {

    public AddFilesWithAESEncryption2() {

        try {
            //Extract Zip files as folders
            try {
                String ZipSourcePath = "E:/EZipTest/";
                String ExtractTo = "D:/DZipTest/";
                String files1;
                File folder1 = new File(ZipSourcePath);
                File[] listOfFiles1 = folder1.listFiles();

                for (int i = 0; i < listOfFiles1.length; i++) {
                    if (listOfFiles1[i].isFile()) {
                        files1 = listOfFiles1[i].getName();
                        String ZipFiles = "E:/EZipTest/" + files1;

                        try {
                            ZipFile zipFile = new ZipFile(ZipFiles);
                            List fileHeaderList = zipFile.getFileHeaders();
                            zipFile.extractAll(ExtractTo);
                        } catch (ZipException e) {
                            e.printStackTrace();
                        }
                    }
                }
                //Get list of folders    
                String DirectoryNames;
                String ExtractedDirectories1 = "D:/DZipTest/";
                File folder2 = new File(ExtractedDirectories1);
                File[] listOfFiles2 = folder2.listFiles();

                for (int i = 0; i < listOfFiles2.length; i++) {
                    if (listOfFiles2[i].isDirectory()) {
                        DirectoryNames = listOfFiles2[i].getName();
                        String ListOfDirectories = "D:/DZipTest/" + DirectoryNames;

                        //Get list of files
                        String ExtractedDirectories = ListOfDirectories;
                        File folder3 = new File(ExtractedDirectories);
                        File[] listOfFiles3 = folder3.listFiles();

                        for (int j = 0; j < listOfFiles3.length; j++) {
                            File file = listOfFiles3[j];
                            if (file.isFile()) {
                                String FileNames = file.getName();
                                System.out.println(ListOfDirectories + FileNames);

                                //Compress and zip the files
                                ZipFile zipFile = new ZipFile("D:/" + listOfFiles2[i].getName() + ".zip");
                                ArrayList filesToAdd = new ArrayList();
                                filesToAdd.add(new File(ListOfDirectories + FileNames));
                                ZipParameters parameters = new ZipParameters();
                                parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE); // set compression method to deflate compression
                                parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
                                parameters.setEncryptFiles(true);
                                parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_AES);
                                parameters.setAesKeyStrength(Zip4jConstants.AES_STRENGTH_256);
                                parameters.setPassword("test");
                                zipFile.addFiles(filesToAdd, parameters);
                            }
                        }
                    }
                }
            } catch (ZipException e) {
                e.printStackTrace();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new AddFilesWithAESEncryption2();
    }
}
4

1 に答える 1

4

リファクタリング

コードをリファクタリングすると、その機能を理解するのに役立ちます。問題を明らかにし、すぐに修正を特定します。これがその方法です。これは完全なチュートリアルではありませんが、要点を理解していただければ幸いです。

まず、解凍を行うナイス メソッドを抽出します。最初のループ内のすべてをマークしfor、右クリックして を選択しますRefactor / Extract Method...。名前を付けてunzipFileください。これで、再利用可能でテスト可能な (JUnit) メソッドが小さくなりました。

次に、ZipParameters parametersからparameters.setPassword("test");右クリックまですべてにマークを付けますRefactor / Extract Method...。名前を付けてgetEncryptionParametersください。long メソッドから 7 行のコードが削除され、読みやすさが向上したことに注目してください。

を右クリックしてparameters、 を選択しますRefactor / Inline ...。一時変数がどのように消えるかに注意してください。

バグを見る

注意深くフォローしている場合は、次のようなコードがあります。

//Compress and zip the files
ZipFile zipFile = new ZipFile("D:/" + listOfFiles2[i].getName() + ".zip");
ArrayList filesToAdd = new ArrayList();
filesToAdd.add(new File(ListOfDirectories + FileNames));
zipFile.addFiles(filesToAdd, getEncryptionParameters());

それが何をするか見てください?新しい ZIP ファイルを作成し、ファイルを1 つfilesToAddだけ追加するだけです。しかし、なぜ?それは言いFileNamesます。どうすればそれが1つのファイルだけになるのでしょうか?

見つめている

String FileNames = file.getName();

これは実際には 1 つのファイルにすぎないため、変数名が間違っています。

右クリックFileNamesして、 を選択しますRefactor/Rename...。を入力しfileNameます。プログラム内の変数名が実際のものとどのように一致するかに注意してください。コードの可読性が大幅に向上します。

簡素化する

1 つのファイルのみを追加することがわかったので、addFile()代わりにaddFiles(). あなたは次のものを取り除きますArrayList

//Compress and zip the files
ZipFile zipFile = new ZipFile("D:/" + listOfFiles2[i].getName() + ".zip");
File fileToAdd = new File(ListOfDirectories + fileName);
zipFile.addFile(fileToAdd, getEncryptionParameters());

バグを修正

前に見たように、 anew ZipFile(...)はループ内に作成され、1 つのファイルのみが追加されます。を押してその行をループの外に移動しますAlt+Up

リファクタリングを続ける

問題の一部は既に修正されていますが (実際には試していません)、コードにエラーがないわけではありません。続けましょう:

次のループFile[] listOfFiles3の最後まですべてをマークします。for右クリックしてRefactor/Extract Method...、名前を付けrezipます。あなたの大きなメソッドは再び小さくなります。

ExtractedDirectories、 を右クリックしますRefactor / Inline ...。不要な一時変数を削除しました。

何か見えますか?コードは次のようになります。

//Get list of files
File folder3 = new File(ListOfDirectories);
rezip(listOfFiles2, i, ListOfDirectories, folder3);

folder3ListOfDirectoriesは本質的に同じであることに注意してください。それを取り除きましょう。行File folder3 = new File(ListOfDirectories);をメソッドのすぐ後ろに移動し、メソッド呼び出しと のメソッド宣言の両方からprivate void rezip(...){パラメーターを削除します。File folder3rezip()

nowを使用するループrezip()は次のようになります。

for (int i = 0; i < listOfFiles2.length; i++) {
    if (listOfFiles2[i].isDirectory()) {
        DirectoryNames = listOfFiles2[i].getName();
        String ListOfDirectories = "D:/DZipTest/" + DirectoryNames;
        rezip(listOfFiles2, i, ListOfDirectories);
    }
}

これDirectoryNamesは実際には 1 つだけであり、多くはありません。右クリック、Refactor/Rename.... を入力しsubDirectoryます。

、 を右クリックsubDirectoryしますRefactor / Inline ...。エラー メッセージを読みます。右クリックしますReferences / Workspace。結果を確認し、この変数がforループ内でのみ使用されていることを確認してください。外部の宣言を削除し、最初の使用時に宣言します。今Refactor / Inline ...操作を行います。

コードは次のようになります。

for (int i = 0; i < listOfFiles2.length; i++) {
    if (listOfFiles2[i].isDirectory()) {
        String ListOfDirectories = "D:/DZipTest/" + listOfFiles2[i].getName();
        rezip(listOfFiles2, i, ListOfDirectories);
    }
}

繰り返しますが、リストまたは配列を示す変数名がありますが、そうではありません。Refactor / Rename...、名前を付けdirectoryToZipます。

次の変数をこの順序でインライン化します: ExtractedDirectories1folder2、。ZipSourcePathfolder1

と の順listOfFiles1に名前zipFilesを変更listOfFiles2extractedDirectoriesます。

未使用のため取り外しfiles1ます。

最後のバグ

メソッドは短くなり、完全に理解できるほど読みやすくなりました。以下は意味がありますか?

String ExtractTo = "D:/DZipTest/";
File[] zipFiles = new File("E:/EZipTest/").listFiles();
for (int i = 0; i < zipFiles.length; i++) {
    unzipFile(ExtractTo, zipFiles, i);
}

File[] extractedDirectories = new File("D:/DZipTest/").listFiles();
for (int i = 0; i < extractedDirectories.length; i++) {
    if (extractedDirectories[i].isDirectory()) {
        String directoryToZip = "D:/DZipTest/" + extractedDirectories[i].getName();
        rezip(extractedDirectories, i, directoryToZip);
    }
}

いいえ、そうではありません。

  1. 最初にすべてのアーカイブを抽出するのではなく、1 つずつ抽出したい
  2. ExtractToサブディレクトリを圧縮するのではなく、ディレクトリ内のすべてを圧縮したい

最後のバグを修正

の署名がunzipFile()正しくないようです。名前が示すように 1 つのファイルのみを解凍する場合、なぜすべてのファイルにアクセスできるのでしょうか?

unzipFile(ExtractTo, zipFiles, i);で置き換えunzipFile(ExtractTo, zipFiles[i]);ます。これにより、コードが壊れます。Eclipse はそれを赤くマークします。からパラメータを変更して修正します

private void unzipFile(String ExtractTo, File[] listOfFiles1, int i)

private void unzipFile(String ExtractTo, File listOfFiles1)

の中で、にunzip置き換えます。それからそれへ。listOfFiles1[i]listOfFiles1Refactor/Rename...sourceZipFile

メソッドについても同様ですrezip。zip するディレクトリとターゲット ファイル名のみを取得する必要があります。したがって、変更

rezip(extractedDirectories, i, directoryToZip);

rezip(extractedDirectories[i], directoryToZip);

次に、メソッド自体をから適応させます

private void rezip(File[] listOfFiles2, int i, String ListOfDirectories) throws ZipException

private void rezip(File listOfFiles2, String ListOfDirectories) throws ZipException

に変更listOfFiles2[i]listOfFiles2ます。に名前を変更しtargetFileます。

これで、素敵なunzipFile()メソッドとrezip()メソッドができました。クールな方法で組み合わせてみましょう。

String ExtractTo = "D:/DZipTest/";
File[] zipFiles = new File("E:/EZipTest/").listFiles();
for (int i = 0; i < zipFiles.length; i++) {
    unzipFile(ExtractTo, zipFiles[i]);
    rezip(zipFiles[i], ExtractTo);
    // TODO: delete extracted files here
}

すごいですね。

ノート

コードを理解し、修正を提供するのにどれだけの労力が必要かをご存知かもしれません。実際、スタック オーバーフローには多大な労力がかかります。次に質問するときは、最低限、現在のコードと同じくらい読みやすいコードを提供するようにしてください。

コードは、本来あるべきほどきれいではありません。もう少し時間をかけてください。すばらしいと思ったら、https://codereview.stackexchange.com/に投稿して、さらに詳しい説明を入手してください。

于 2015-06-25T10:04:47.093 に答える