为何relativize方法无法正确处理Jar资源路径?
为什么URI的relativize方法无法处理Jar资源路径?
问题本质
URI.relativize()的核心逻辑是:仅能处理同协议、且路径存在父子层级关系的URI,而Jar URI的特殊结构导致它无法被该方法正确解析:
- 协议不匹配:
jarUrl是file协议的URI(指向Jar文件本身),而resourceUrl是jar协议的URI(指向Jar内部资源),两者协议不同,relativize()直接返回原URI,不会尝试生成相对路径。 - Jar URI结构不被识别:Jar URI的格式是
jar:<file-uri>!/<entry-path>,relativize()不会把!后面的内容当作Jar内部的路径层级,它只会把整个jar:file:/xxx.jar!/当作一个完整的路径前缀,无法识别!/mydir/myresource.txt是!/的子路径,因此也无法生成相对路径。
解决方法
要获取Jar资源相对于Jar根的路径,需要手动解析Jar URI的特殊结构,以下两种方案都能实现需求:
方案1:字符串直接拆分
直接截取Jar URI中!之后的部分,就是资源相对于Jar根的路径:
// 处理资源URI String resourceUriStr = resourceUrl.toURI().toString(); int bangIndex = resourceUriStr.indexOf("!/"); if (bangIndex != -1) { // 相对于Jar根的路径 String relativeToRoot = resourceUriStr.substring(bangIndex + 2); // 相对于Jar文件本身的路径(带/前缀) String relativeToJarFile = resourceUriStr.substring(bangIndex + 1); System.out.println(relativeToJarFile); // 输出 /mydir/myresource.txt System.out.println(relativeToRoot); // 输出 mydir/myresource.txt }
方案2:使用JarURLConnection
通过JarURLConnection可以直接获取Jar条目的名称,这就是资源相对于Jar根的路径:
JarURLConnection jarConn = (JarURLConnection) resourceUrl.openConnection(); String entryName = jarConn.getEntryName(); System.out.println(entryName); // 输出 mydir/myresource.txt
修改后的完整示例
// 网站示例(验证relativize正常工作) URL website = new URL("https://stackoverflow.com/"); URL webpage = new URL("https://stackoverflow.com/help/how-to-answer"); URI webRelative = website.toURI().relativize(webpage.toURI()); // Jar相关路径 URL jarUrl = new URL("file:/C:/Users/cardinal/Desktop/Test.jar"); URL resourceUrl = new URL("jar:file:/C:/Users/cardinal/Desktop/Test.jar!/mydir/myresource.txt"); // 解析Jar相对路径 String resourceUriStr = resourceUrl.toURI().toString(); int bangPos = resourceUriStr.indexOf("!/"); String relativeToJarFile = bangPos != -1 ? resourceUriStr.substring(bangPos + 1) : ""; String relativeToJarRoot = bangPos != -1 ? resourceUriStr.substring(bangPos + 2) : ""; // 输出结果 System.out.println(webRelative); System.out.println(relativeToJarFile); System.out.println(relativeToJarRoot);
运行输出将符合预期:
help/how-to-answer /mydir/myresource.txt mydir/myresource.txt
内容的提问来源于stack exchange,提问作者Cardinal System
相关产品推荐
相关产品推荐

