3

我正在尝试从文件夹中提取 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();
    }
}
4

1 回答 1

4

重构

重构你的代码将帮助你理解它的作用。它将揭示问题并立即确定修复程序。事情是这样的。请注意,这不是一个完整的教程,但我希望你明白这一点。

首先,提取一个很好的解压缩方法。标记第一个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(...)在循环中创建了 a,并且只添加了一个文件。按 将该行移出循环Alt+Up

继续重构

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

标记从后面的循环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 folder3rezip()

现在使用的循环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

按此顺序内联以下变量:ExtractedDirectories1, folder2, ZipSourcePath, folder1.

按此顺序重命名listOfFiles1zipFiles和。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. 您不想先提取所有档案,而是一个一个地提取
  2. 您不想压缩子目录,而是想压缩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
}

太棒了,不是吗?

笔记

也许您已经看到理解您的代码并提供修复需要付出多少努力。实际上,Stack Overflow 付出了太多的努力。下次您提出问题时,请尝试提供与您现在的代码一样可读的代码。

代码仍然没有应有的干净。多花点时间在上面。如果您认为它很棒,请将其发布在https://codereview.stackexchange.com/上以获取更多说明。

于 2015-06-25T10:04:47.093 回答