删除压缩文件中的目录
看到有朋友在问如何删除压缩文件中的目录,在这里补充一下。
利用zip4j删除压缩文件中的目录,查阅API后很容易想到这样的方式:
ZipFile zipFile = new ZipFile("d:\\FeiQ-V2.5.zip");
zipFile.setFileNameCharset("GBK");
zipFile.removeFile("sounds/"); // sounds是zip文件中的一个目录
但这种直接删除压缩文件中非空目录的方式是不会成功的,你会看到zip文件丝毫没有变化,虽然目录对应的FileHeader已被删除(表现就是如果这时再将目录下的所有文件删除,则该目录随之消失) ;因此我们需要将该目录下所有的文件都删除掉,最后再将目录删除,根据这个思路,我们很容易形成如下的代码:
void removeDirFromZipArchive(String file, String removeDir) throws ZipException {
// 创建ZipFile并设置编码
ZipFile zipFile = new ZipFile(file);
zipFile.setFileNameCharset("GBK");
// 给要删除的目录加上路径分隔符
if (!removeDir.endsWith(File.separator)) removeDir += File.separator;
// 如果目录不存在, 直接返回
FileHeader dirHeader = zipFile.getFileHeader(removeDir);
if (null == dirHeader) return;
// 遍历压缩文件中所有的FileHeader, 将指定删除目录下的子文件删除
List allHeaders = zipFile.getFileHeaders();
for(int i=0, len = allHeaders.size(); i<len; i++) {
FileHeader subHeader = (FileHeader) allHeaders.get(i);
if (subHeader.getFileName().startsWith(dirHeader.getFileName())
&& !subHeader.getFileName().equals(dirHeader.getFileName())) {
zipFile.removeFile(subHeader);
}
}
// 最后删除指定目录
zipFile.removeFile(dirHeader);
}
这样仍然解决不了问题,如果你这样做了,那么你将会得到一个Java.lang.IndexOutOfBoundsException异常,那么看似正常的代码为什么会报索引越界异常呢?其实我们通过zipFile.getFileHeaders()方法得到的List会随遍历中的删除操作而发生变化,也就是说我们删除了某个FileHeader,将会反映到该List中。每成功删除一个FileHeader,List长度就减1,而i一直在0至List的初始长度之间递增,反复几次后就可能出现越界异常。
为了避免这种情况发生,我们可以多做一些操作,比如可以在遍历中暂不进行删除操作,而只是将要删除的文件记录下来,遍历结束后再统一删除,最后将目录删除,经测试,这个思路可以解决问题。
简单示例代码:
void removeDirFromZipArchive(String file, String removeDir) throws ZipException {
// 创建ZipFile并设置编码
ZipFile zipFile = new ZipFile(file);
zipFile.setFileNameCharset("GBK");
// 给要删除的目录加上路径分隔符
if (!removeDir.endsWith(File.separator)) removeDir += File.separator;
// 如果目录不存在, 直接返回
FileHeader dirHeader = zipFile.getFileHeader(removeDir);
if (null == dirHeader) return;
// 遍历压缩文件中所有的FileHeader, 将指定删除目录下的子文件名保存起来
List headersList = zipFile.getFileHeaders();
List<String> removeHeaderNames = new ArrayList<String>();
for(int i=0, len = headersList.size(); i<len; i++) {
FileHeader subHeader = (FileHeader) headersList.get(i);
if (subHeader.getFileName().startsWith(dirHeader.getFileName())
&& !subHeader.getFileName().equals(dirHeader.getFileName())) {
removeHeaderNames.add(subHeader.getFileName());
}
}
// 遍历删除指定目录下的所有子文件, 最后删除指定目录(此时已为空目录)
for(String headerNameString : removeHeaderNames) {
zipFile.removeFile(headerNameString);
}
zipFile.removeFile(dirHeader);
}
也许还有其它的办法来解决此问题,如果您有需要,就留待您来解决了。