目录

相对路径

类路径

总结


如果涉及文件相关的编程,文件路径这一块肯定是避不开的。

以前一直对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");

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐