刚接触 Java 的小伙伴,都学习过使用
绝对路径的概念:
相对路径的概念:
举个例子:假设有一个 Java 源文件 Example.java 在 D 盘根目录下,那么它的绝对路径地址就是 D:\Example.java。如果我们使用 javac Example.java 命令来编译此文件,然后在 D 盘根目录下再调用 java Example 来运行此文件,此时我们就启动了一个 jvm 进程,这个 jvm 进程是在 D 盘根目录下被启动的,所以此时 jvm 所加载的程序中 File 类的相对路径就是相对于这个路径的。
1 | import java.io.File; |
假设 jvm 是在 “D:\” 下启动的,那么 hello.txt 就会生成在 D:\hello.txt。
假设 jvm 是在 “C:\” 下启动的,那么 hello.txt 就会生成在 C:\hello.txt。
user.dir
JDK 官方文档对 user.dir 的解释:User’s current working directory.
翻译过来就是 “
1 | System.getProperty("user.dir"); // 返回值 D:\ |
但是,JDK 官方文档中也有说明 user.dir 是一个可配置的 jvm 启动参数,通过以下命令启动 Java 程序就可以修改 user.dir 的值:
1 | java -Duser.dir="D:\demo" Example |
然而,通过以上命令再次执行 Example 程序,会报 java.lang.ClassNotFoundException 错误,因为当前程序的工作目录已经被修改为 D:\demo 了,所以 jvm 进程虽然在 D:\ 下被启动,但会去 D:\demo 工作目录中加载 Example 类:
1 | D:\>java -Duser.dir="d:\\demo" Example |
如果我们把编译好的 Example.class 复制到 D:\demo 中,就可以执行成功。并且读取到的 user.dir 确实是我们修改后的目录:
1 | D:\>java -Duser.dir="d:\\demo" Example |
注意看上面的执行命令,我们是在 D:\ 目录下执行的 java 命令,jvm 进程也在这里启动,虽然我们修改了 user.dir 启动参数,但是我们创建的 hello.txt 文件,依然被创建在了 D:\hello.txt,而不是我们以为的 D:\demo\hello.txt。
还记得我们之前说的相对路径的概念吗,
java.io.File 类
JDK 官方文档中针对 File 类的相对路径有这么一段描述:
A pathname, whether abstract or in string form, may be either absolute or relative. An absolute pathname is complete in that no other information is required in order to locate the file that it denotes. A relative pathname, in contrast, must be interpreted in terms of information taken from some other pathname. By default the classes in the
java.iopackage always resolve relative pathnames against the current user directory. This directory is named by the system propertyuser.dir, and is typically the directory in which the Java virtual machine was invoked.
一个路径,无论是抽象的还是字符串形式的,都无非是绝对路径或相对路径。绝对路径是完整的,因为不需要再补充其它信息来定位它所指示的文件。相比之下,相对路径必须根据来自其它路径的信息来进行解释。
改写我们刚才的程序:
1 | import java.io.File; |
在 D:\ 下执行,会创建 D:\hello.txt 文件:
1 | D:\>java Example |
把 D:\hello.txt 删除掉,在 D:\ 下执行程序,但是人为修改 jvm 的 user.dir 属性:
1 | D:\>java -Duser.dir="d:\\demo" Example |
查看下 D 盘根目录,对的,你没有看错,真实创建的文件依然是 D:\hello.txt,而不是我们以为的 D:\demo\hello.txt。但是 File 类的方法,确实是受到了 user.dir 的影响,getAbsolutePath 方法返回的值是相对于 user.dir 的,与真实创建的文件不能对应。
结论:
Java 操作文件时,如果给定的是相对路径,Java 会使用 JVM 进程的启动路径作为参照来处理文件。但是 java.io 包在处理相对路径时,总是根据用户的当前工作目录来解析相对路径。
所以,我们在处理文件的时候,最好都先把文件转换为绝对路径,再进行操作。
Linux 和 Windows 路径分隔符
Linux 下:“/”
Windows 下:“\”
Java 中获取系统分隔符:System.getProperty(“file.separator”)
参考资料
https://docs.oracle.com/javase/tutorial/essential/io/path.html
https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/lang/System.html#getProperties()