Java处理zip压缩文件的完整解决方案(3)

删除压缩文件中的目录

看到有朋友在问如何删除压缩文件中的目录,在这里补充一下。

利用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);
}

也许还有其它的办法来解决此问题,如果您有需要,就留待您来解决了。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/89a4de838c1fedc8ba948cf932c7776b.html