Java提取JAR包时的文件名大小写冲突问题
解决Mac上Shadow JAR解压时的大小写冲突问题
嘿,我遇到过几乎一模一样的问题!核心原因是Mac默认的APFS文件系统是大小写不敏感但保留大小写显示的——这就导致JAR里看似不同的路径(比如license文件和LICENSE/目录),在Mac上会被识别成同一个路径,解压时自然就冲突了。
问题根源
你的Shadow JAR里应该同时存在两种冲突条目:要么是先出现一个叫license的普通文件,之后又出现LICENSE/licence.txt的目录+文件;要么是反过来的顺序。在Mac的文件系统中,LICENSE和license被视为同一个路径,当代码尝试创建目录时,发现这个路径已经被一个文件占用,就会抛出Not a directory的错误——你看到的MANIFEST.MF报错只是冲突的其中一个表现,本质都是大小写导致的路径冲突。
你的代码哪里出问题了?
当前的解压代码有两个关键漏洞:
- 没判断ZipEntry是否是目录:不管是文件还是目录,你都直接创建
FileOutputStream,如果是目录的话肯定会出错; - 没处理大小写冲突:针对Mac这类大小写不敏感的文件系统,没有提前检查路径是否被同名(不区分大小写)的文件/目录占用。
修复后的完整代码
我给你修改了解压函数,解决了这些问题,还加了try-with-resources来避免资源泄漏:
public void unZipIt(String zipFile, String outputFolder) { byte[] buffer = new byte[1024]; try { // 创建输出目录(用mkdirs确保多级目录都能创建) File outputDir = new File(outputFolder); if (!outputDir.exists()) { outputDir.mkdirs(); } // try-with-resources自动关闭流,避免资源泄漏 try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) { ZipEntry entry = zis.getNextEntry(); while (entry != null) { String entryName = entry.getName(); File targetFile = new File(outputFolder + File.separator + entryName); System.out.println("Processing: " + targetFile.getAbsolutePath()); if (entry.isDirectory()) { // 处理目录:如果存在同名文件,先删除再创建目录 if (targetFile.exists()) { if (targetFile.isFile()) { targetFile.delete(); } } targetFile.mkdirs(); } else { // 处理文件:先确保父目录存在,解决大小写冲突 File parentDir = targetFile.getParentFile(); if (parentDir != null) { if (parentDir.exists()) { if (parentDir.isFile()) { parentDir.delete(); } } else { parentDir.mkdirs(); } } // 写入文件内容 try (FileOutputStream fos = new FileOutputStream(targetFile)) { int readLen; while ((readLen = zis.read(buffer)) > 0) { fos.write(buffer, 0, readLen); } } } zis.closeEntry(); entry = zis.getNextEntry(); } } System.out.println("解压完成!"); } catch (IOException ex) { ex.printStackTrace(); } }
从源头上避免问题的建议
比起解压时修复,更稳妥的是在生成Shadow JAR时就排除冲突的条目。比如在你的build.gradle里配置shadowJar任务,去掉重复的license相关条目:
shadowJar { // 排除根目录下的license文件,保留LICENSE目录下的文件 exclude 'license' // 如果有其他大小写冲突的条目,也可以在这里排除 }
这样生成的JAR里就不会有冲突的路径,解压时自然不会出错啦!
内容的提问来源于stack exchange,提问作者Vitali Melamud
相关产品推荐
相关产品推荐

