我试图从文件夹中提取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 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文件,仅将一个文件添加到
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
。您的大方法再次变小。右键单击
ExtractedDirectories
和Refactor / Inline ...
。您只是摆脱了不必要的临时变量。有事吗您的代码应如下所示:
//Get list of files
File folder3 = new File(ListOfDirectories);
rezip(listOfFiles2, i, ListOfDirectories, folder3);
注意
folder3
和ListOfDirectories
本质上是一样的。让我们摆脱它。将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
。右键单击
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
。按此顺序内联以下变量:
ExtractedDirectories1
,folder2
,ZipSourcePath
,folder1
。以此顺序将
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/上以获得更多说明。