Java相对路径与类路径详解
相对的是工作目录# 相对的是class文件所在的根目录# 相对的是ClassPathDemo.class所在的目录# 相对的是class文件所在的根目录,并且一定不能加斜杠。
目录
如果涉及文件相关的编程,文件路径这一块肯定是避不开的。
以前一直对Java中的相对路径理解的不是很深刻,今天又重新理解了一下,整理如下。
绝对路径就不多说了,linux中以斜杠开头,windows中需要以磁盘符开头,比较简单,重点放在相对路径 和 类路径(classpath)。
相对路径
相对路径相对的是哪个路径?
相对的是工作目录。
重点是要理解什么是工作目录:其实就是执行命令时,终端(命令行)所在的当前目录(linux中中pwd的执行结果)。
下面通过一个例子来说明
新建一个maven项目,目录结构如下
src下是源码,target下是编译后的class文件。
hello.txt是我们需要读取的文件, 直接放在项目的根目录下(netty-demo文件夹下)。
FilePathDemo用于测试相对路径,代码如下:
public class FilePathDemo {
public static void main(String[] args) {
File file = new File("hello.txt");
//判断文件是否存在
System.out.println(file.exists());
//获取当前目录
System.out.println("current dir: " + System.getProperty("user.dir"));
}
}
其中 System.getProperty("user.dir") 用于获取工作目录。
首先直接通过idea提供的执行按钮执行程序
结果为
工作目录为 netty-demo文件夹所在路径,并且可以获取到hello.txt文件。
点击执行按钮后,idea实际执行了下面的命令
缩减一下不重要的部分后就是
java -classpath "E:\java\demo\netty-demo\target\classes" com.dayrain.nio.FilePathDemo
通过-classpath指定项目class所在的目录。
打开终端,执行上述命令,可以得到同样的结果
红框中的 E:\java\demo\netty-demo 就是所谓的工作目录;
如果我们随意切换一个目录,执行同样的命令,会发现找不到文件了。
此时的工作目录切换为 “E:\java\demo\netty-demo\target\classes”。classes下没有hellot.txt文件,自然找不到。
进一步验证,把hello.txt直接拖到classes目录下:
再执行命令,就可以获取到文件。
所以说,“相对目录”相对的是工作目录,也就是你执行命令时所在的当前目录。
类路径
项目中直接用上面的方式读取文件是不合适的,因为用户的工作目录未必一定是固定的。
所以会有另一种相对路径:类路径。
类路径也是一种特殊的相对路径,只不过它相对的是class文件。
maven管理的项目,默认情况下resource目录下的文件会被放置类路径下。
以一个普通的springboot项目为例:
application.properties文件最后会放在类路径下,即classes文件夹下,和com文件夹同目录。
回到上面的演示代码
注意com包和hello.txt文件在统一目录下
ClassPathDemo源码为
package com.dayrain.nio;
import java.net.URL;
public class ClassPathDemo {
public static void main(String[] args){
URL resource = ClassPathDemo.class.getResource("/hello.txt");
if(resource == null) {
System.out.println("file not exists");
}else {
System.out.println(resource);
}
}
}
执行结果为
比较细心的同学应该可以发现,源码中“/hello.txt”用的是绝对路径
类路径是有绝对路径的,也就是classes文件夹所在的路径。(E:/java/demo/netty-demo/target/classes/)
这么说也不太准确,因为不同项目的打包方式不一样,有的项目源码不一定都放在classes文件夹下,也可能会换个其他名字。主要是看类文件存放的路径,如果class文件的包结构为com.dayrain.nio,那类路径的绝对路径就是com文件夹的父目录。
如果我们把绝对路径换成相对路径,则会找不到文件。
类路径的相对路径其实就是当前class文件所在的路径,也就是下面ClassPathDemo.class所在的目录。
为了验证这一说法,将hello.txt文件拖拽至nio目录下,即可成功读取,代码和结果如下:
上面的这种写法用的比较少,局限性太大,一般还是通过类路径的根目录定位。
还有一种很常见的写法,通过类加载器来加载提供的api加载文件。
ClassPathDemo.class.getClassLoader().getResource("hello.txt");
这种写法前面不能加斜杠,加斜杠后获取到的结果永远是null。通过类加载器读取资源时,直接会把类路径的根目录作为起点。
也就是说下面两种写法是等价的。
URL resource = ClassPathDemo.class.getResource("/hello.txt");
URL resource = ClassPathDemo.class.getClassLoader().getResource("hello.txt");
这里容易混淆,但其实也很容易理解,通过某个class获取资源时,以这个class文件所在的目录为参照物,如果你想以根目录为参照物,则必须加个斜杠;而通过类加载器加载资源时,没有明确的起点,只能都按照根目录作为参照物,干脆统一都不加斜杠算了。
总结
# 相对的是工作目录
File file = new File("hello.txt")
# 相对的是class文件所在的根目录
URL resource = ClassPathDemo.class.getResource("/");
# 相对的是ClassPathDemo.class所在的目录
URL resource = ClassPathDemo.class.getResource("a/b/c");
# 相对的是class文件所在的根目录,并且一定不能加斜杠
URL resource = ClassPathDemo.class.getClassLoader().getResource("hello.txt");
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)