Ubuntu下获取Jar文件相对路径失败问题求助
问题分析与解决方案
你的问题核心在于Java的File类和shell对路径的解析逻辑完全不同,导致同样的路径写法在两种环境下表现不一。
为什么Linux下代码报错?
当你在Linux中拿到jarPath时,它是指向Jar文件本身的路径(比如/some/directory/where/xml/is/located/xyz.jar)。直接拼接/../../configurationFile.xml后,得到的路径是:
/some/directory/where/xml/is/located/xyz.jar/../../configurationFile.xml
Java的File类会尝试把xyz.jar当作一个目录来访问,但它本质是个文件,自然会抛出"Not a directory"的错误——因为你无法进入一个文件内部再用..回退目录。
为什么shell命令能正常工作?
shell在解析路径时,是先拆分路径的各个片段,再逻辑上处理..,而不是去实际检查每个片段是否是目录。比如pwd /some/dir/xyz.jar/../../会被shell拆解为:
- 先识别
/some/dir/xyz.jar这个路径片段 - 遇到第一个
..,直接回退到上一级目录/some/dir - 遇到第二个
..,再回退到/some
整个过程不需要实际进入xyz.jar这个文件,所以能正常返回正确的上级目录。
正确的Java实现方式
你需要先获取Jar文件所在的目录,再从该目录往上回退两级,而不是直接在Jar文件路径后拼接../。推荐使用Java 7+的Path API,它的路径处理更符合预期:
import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; import java.io.File; // 获取Jar文件的位置URL URL jarLocation = Configuration.class.getProtectionDomain().getCodeSource().getLocation(); // 转换为Path对象(自动处理URL编码问题) Path jarPath = Paths.get(jarLocation.toURI()); // 先拿到Jar所在的目录,再往上回退两级,最后拼接配置文件名 Path configFilePath = jarPath.getParent().getParent().resolve("configurationFile.xml"); // 转换为File对象(如果需要的话) File configFile = configFilePath.toFile();
如果你还在使用Java 6及以下版本,可以用File的API实现:
import java.net.URL; import java.io.File; URL jarLocation = Configuration.class.getProtectionDomain().getCodeSource().getLocation(); File jarFile = new File(jarLocation.toURI()); // 获取Jar所在的目录 File jarDir = jarFile.getParentFile(); // 往上回退两级目录 File targetDir = jarDir.getParentFile().getParentFile(); File configFile = new File(targetDir, "configurationFile.xml");
额外注意事项
- 如果你的代码是在IDE中直接运行(而非打包成Jar),
getCodeSource().getLocation()返回的会是类文件所在的目录,这时候需要添加判断逻辑,避免空指针或路径错误。 - 建议使用
URI转换而非直接拼接路径字符串,避免空格、特殊字符等导致的编码问题。
内容的提问来源于stack exchange,提问作者Bernd
相关产品推荐
相关产品推荐

