我试图从文件夹中提取zip文件列表,然后使用密码重新压缩它们。问题在于重新压缩时,迭代/循环没有停止。同样,重新压缩的文件应该是每个单独的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();
    }
}

最佳答案

重构

重构代码将帮助您了解其功能。它将发现问题并立即确定解决方案。这是怎么回事。请注意,这不是完整的教程,但是希望您能理解。

首先,提取一个不错的方法来解压缩。标记第一个for循环内的所有内容,然后右键单击并选择Refactor / Extract Method...。将其命名为unzipFile。请注意,您现在有了一个不错的小型,潜在可重用和潜在可测试(JUnit)的方法。

接下来,标记从ZipParameters parametersparameters.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文件,仅将一个文件添加到filesToAdd中,仅此而已。但为什么?它说FileNames。那怎么只能是一个文件?

看着
String FileNames = file.getName();

那实际上只是一个文件,所以变量名是错误的。

右键单击FileNames,然后选择Refactor/Rename...。输入fileName。请注意程序中的变量名如何与其实际匹配。它极大地提高了代码的可读性。

简化

现在您知道只添加了一个文件,请使用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());

修正错误

如前所述,在循环内部创建了一个new ZipFile(...),并且仅向其中添加了一个文件。按下Alt +向上键将该行移出循环。

继续重构

问题的一部分已经解决(实际上,我还没有尝试过),但是您的代码仍然不是没有错误的。我们继续:

标记所有内容,从File[] listOfFiles3到随后的for循环的结尾。右键单击Refactor/Extract Method...,将其命名为rezip。您的大方法再次变小。

右键单击ExtractedDirectoriesRefactor / 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 folder3的方法调用和方法声明中都删除参数rezip()

现在,使用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实际上只是一个,而不是很多。右键单击Refactor/Rename...。输入subDirectory

右键单击subDirectoryRefactor / 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

按此顺序内联以下变量:ExtractedDirectories1folder2ZipSourcePathfolder1

以此顺序将listOfFiles1重命名为zipFiles,并将listOfFiles2重命名为extractedDirectories

删除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);
    }
}

不,不是。
  • 您不想首先提取所有存档,而是一个接一个地提取
  • 您不想压缩子目录,而是想压缩ExtractTo目录中的所有内容

  • 修复最后的错误
    unzipFile()的签名看起来不正确。如果仅按名称所示解压缩一个文件,那么为什么它才能访问所有文件?

    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]替换为listOfFiles1。然后Refactor/Rename...sourceZipFile

    rezip方法类似:它应仅获取要压缩的目录和目标文件名。因此改变
    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/上以获得更多说明。

    07-25 22:47