springboot中File默认路径

1. 背景

在Springboot项目开发中,针对文件解析类业务,以及文件生成类业务,正对默认的文件路径比较容易混淆,这里通过代码示例,记录每一种方式对应的默认路径.方便以后开发中快速查询.

项目信息如下:

  • 项目目录: D:\projects\javaprj
  • 项目名称: springboottest
  • POM文件路径: D:\projects\javaprj\springboottest\pom.xml

需要依次测试一下几种情况

  • 参数为 ""
  • 参数为 "."
  • 参数为 "./"
  • 参数为 "../"
  • 参数为 "/"

2. 获取文件(资源)几种方式

3. 通过File类获取文件默认路径

File通过File(String pathname)构造函数传递具体的路径信息,得到文件默认路径.getCanonicalPath是获取对应串的真实路径,路径上会去掉路径相对表示*../*.测试代码如下:

复制代码
// 小游戏 地心侠士 公众号:小满小慢 
public static void filePath() throws IOException {
  System.out.println("=========小游戏 地心侠士 File类默认路径=========");
  File file = new File("");
  System.out.println("File \"\"   路径: " + file.getCanonicalPath());
  file = new File(".");
  System.out.println("File \".\"  路径: " + file.getCanonicalPath());
  file = new File("./");
  System.out.println("File \"./\" 路径: " + file.getCanonicalPath());
  file = new File("../");
  System.out.println("File \"../\"路径: " + file.getCanonicalPath());
  file = new File("/");
  System.out.println("File \"/\" 路径: " + file.getCanonicalPath());
}

以上代码对应输输出结果如下:

复制代码
=========小游戏 地心侠士 File类默认路径=========
File ""   路径: D:\projects\javaprj\springboottest
File "."  路径: D:\projects\javaprj\springboottest
File "./" 路径: D:\projects\javaprj\springboottest
File "../"路径: D:\projects\javaprj
File "/" 路径: D:\

打包把springboottest-0.0.1-SNAPSHOT.jar放在D:\,jdk所在的目录:C:\Program Files\Java\jdk17.0.8\bin,切换到jdk所在的目录执行如下命令:java -jar d:\springboottest-0.0.1-SNAPSHOT.jar,得到的输出结果如下:

复制代码
=========小游戏 地心侠士 File类默认路径=========
File ""   路径: C:\Program Files\Java\jdk17.0.8\bin
File "."  路径: C:\Program Files\Java\jdk17.0.8\bin
File "./" 路径: C:\Program Files\Java\jdk17.0.8\bin
File "../"路径: C:\Program Files\Java\jdk17.0.8
File "/" 路径: C:\

切换到jar所在目录执行如下命令:"C:\Program Files\Java\jdk17.0.8\bin\java.exe" -jar springboottest-0.0.1-SNAPSHOT.jar

得到的输出结果如下:

复制代码
=========小游戏 地心侠士 File类默认路径=========
File ""   路径: D:\
File "."  路径: D:\
File "./" 路径: D:\
File "../"路径: D:\
File "/" 路径: D:\

从以上场景中,可以知道在调用File(String pathname)构造函数时,得到如下结论

  • 参数" ",".","./"都指向相同的目录.
  • 支持相对目录写法, 如"../"会向上一级目录.
  • 参数"/",表示获取工作目录的跟目录
  • 默认目录和jar包所在的目录并没有关系.只和工作目录有关系

可以通过以下代码获取到工作目录:

复制代码
--小游戏 地心侠士
String workingDir = System.getProperty("user.dir");
System.out.println("当前工作目录为: "+workingDir);

如果想要输出目录始终一直,可以在启动时指定工作目录,可以使用-Duser.dir修改,如启动命令调整为:java -Duser.dir=D:\ -jar d:\springboottest-0.0.1-SNAPSHOT.jar此时,Filel类的默认目录一定是为D:\

4. 通过Class类获取文件默认路径

使用class的getResource()方法获取文件默认路径.为了说明问题,特地使用处于不同包的两个类测试

  • com.RootClass

  • com.herbert.springboottest.SpringboottestApplication
    测试代码如下:

    public static void classgetResource() {
    System.out.println("===小游戏 地心侠士 class.getResource 默认路径===");
    URL resource = SpringboottestApplication.class.getResource("");
    System.out.println("class.getResource "" 路径: " + resource.getPath());
    resource = SpringboottestApplication.class.getResource(".");
    System.out.println("class.getResource "." 路径: " + resource.getPath());
    resource = SpringboottestApplication.class.getResource("./");
    System.out.println("class.getResource "./"路径: " + resource.getPath());
    resource = SpringboottestApplication.class.getResource("../");
    System.out.println("class.getResource "../"路径: " + resource.getPath());
    resource = SpringboottestApplication.class.getResource("/");
    System.out.println("class.getResource "/" 路径: " + resource.getPath());
    }

以上代码对应的输出结果如下:

复制代码
===小游戏 地心侠士 class.getResource 默认路径===
class.getResource ""   路径: /D:/projects/javaprj/springboottest/target/classes/com/herbert/springboottest/
class.getResource "."  路径: /D:/projects/javaprj/springboottest/target/classes/com/herbert/springboottest/
class.getResource "./"路径: /D:/projects/javaprj/springboottest/target/classes/com/herbert/springboottest/
class.getResource "../"路径: /D:/projects/javaprj/springboottest/target/classes/com/herbert/
class.getResource "/" 路径: /D:/projects/javaprj/springboottest/target/classes/
RootClass.getResource "" 路径: /D:/projects/javaprj/springboottest/target/classes/com/

打包成jar后执行,不管工作目录如何,class.getResource()方法得到的目录都是jar包所在目录.

复制代码
===小游戏 地心侠士 class.getResource 默认路径===
class.getResource ""   路径: nested:/D:/springboottest-0.0.1-SNAPSHOT.jar/!BOOT-INF/classes/!/com/herbert/springboottest/
class.getResource "."  路径: nested:/D:/springboottest-0.0.1-SNAPSHOT.jar/!BOOT-INF/classes/!/com/herbert/springboottest/
class.getResource "./"路径: nested:/D:/springboottest-0.0.1-SNAPSHOT.jar/!BOOT-INF/classes/!/com/herbert/springboottest/
class.getResource "../"路径: nested:/D:/springboottest-0.0.1-SNAPSHOT.jar/!BOOT-INF/classes/!/com/herbert/
class.getResource "/" 路径: nested:/D:/springboottest-0.0.1-SNAPSHOT.jar/!BOOT-INF/classes/!/
RootClass.getResource "" 路径: nested:/D:/springboottest-0.0.1-SNAPSHOT.jar/!BOOT-INF/classes/!/com/

从测试结果可以知道

  • " ",".","." 都指向当前class所在的目录.
  • 支持相对目录写法, 如"../"会向上一级目录.
  • "/"指向classes目录或者class所在jar的根目录.
  • 和工作目录没有关系.和class在哪里有关系

5. 通过ClassLoader类获取文件默认路径

使用classloader的getResource()方法获取文件默认路径

测试代码如下:

复制代码
public static void classLoaderGetResource(ClassLoader classLoader) {
  System.out.println("===小游戏 地心侠士 classLoader.getResource 默认路径===");
  System.out.println("classLoader信息: " + classLoader.getName() + " " + classLoader.getClass().getSimpleName());
  URL resource = classLoader.getResource("application.properties");
  System.out.println("classLoader.getResource \"\" 路径: " + resource.getPath());
  resource = classLoader.getResource(".");
  System.out.println("classLoader.getResource \".\" 路径: " + resource.getPath());
  resource = classLoader.getResource("./");
  System.out.println("classLoader.getResource \"./\" 路径: " + resource.getPath());
  resource = classLoader.getResource("com");
  System.out.println("classLoader.getResource \"com\" 路径: " + resource.getPath());
  // 不支持上级目录
  resource = classLoader.getResource("../");
  if (resource != null) {
  	System.out.println("classLoader.getResource \"../\" 路径: " + resource.getPath());
  } else {
  	System.out.println("classLoader.getResource \"../\" 路径: 不支持 ");
  }
  // 不支持绝对目录
  resource = classLoader.getResource("/");
  System.out.println("classLoader.getResource \"/\" 路径:  不支持");
}
  • AppClassLoader 执行情况

测试代码: classLoaderGetResource(ClassLoader.getSystemClassLoader()) 在IDE中输输出结果如下:

复制代码
===小游戏 地心侠士 classLoader.getResource 默认路径===
classLoader信息: app AppClassLoader
classLoader.getResource "" 路径: /D:/projects/javaprj/springboottest/target/classes/application.properties
classLoader.getResource "." 路径: /D:/projects/javaprj/springboottest/target/classes/
classLoader.getResource "./" 路径: /D:/projects/javaprj/springboottest/target/classes/
classLoader.getResource "com" 路径: /D:/projects/javaprj/springboottest/target/classes/com
classLoader.getResource "../" 路径: 不支持 
classLoader.getResource "/" 路径:  不支持

打包成jar后执行,直接获取不到resouce,直接报错,可能与我打包的fat包有关系.

  • PlatformClassLoader 执行情况

测试代码: classLoaderGetResource(ClassLoader.getPlatformClassLoader()) 在IDE中输输出结果如下:

无论是IDE中,还是打包成jar执行,都获取不到对应resource.

通过两类系统classloader的测试,总结如下

  • classLoader.getResource 受类加载器影响明显,不建议直接使用
  • class.getResource 相对于类所在路径,比较清晰

6. 使用ResourceUtils获取资源

Spring提供的工具类了 ResourceUtils 获取资源,测试代码如下

复制代码
public static void springResourceUtilsFilePath() throws IOException {
  System.out.println("=========小游戏 地心侠士 ResourceUtils类默认路径=========");
  File file = ResourceUtils.getFile("");
  System.out.println("ResourceUtils \"\"   路径: " + file.getCanonicalPath());
  file = ResourceUtils.getFile(".");
  System.out.println("ResourceUtils \".\"  路径: " + file.getCanonicalPath());
  file = ResourceUtils.getFile("./");
  System.out.println("ResourceUtils \"./\" 路径: " + file.getCanonicalPath());
  file = ResourceUtils.getFile("../");
  System.out.println("ResourceUtils \"../\"路径: " + file.getCanonicalPath());
  file = ResourceUtils.getFile("/");
  System.out.println("ResourceUtils \"/\" 路径: " + file.getCanonicalPath());
  file = ResourceUtils.getFile("classpath:application.properties");
  System.out.println("ResourceUtils  classpath: 路径: " + file.getCanonicalPath());
  file = ResourceUtils.getFile("file:application.properties");
  System.out.println("ResourceUtils file: 路径: " + file.getCanonicalPath());
}

IDE运行后输出结果如下

复制代码
=========小游戏 地心侠士 ResourceUtils类默认路径=========
ResourceUtils ""   路径: D:\projects\javaprj\springboottest
ResourceUtils "."  路径: D:\projects\javaprj\springboottest
ResourceUtils "./" 路径: D:\projects\javaprj\springboottest
ResourceUtils "../"路径: D:\projects\javaprj
ResourceUtils "/" 路径: D:\
ResourceUtils  classpath: 路径: D:\projects\javaprj\springboottest\target\classes\application.properties
ResourceUtils file: 路径: D:\projects\javaprj\springboottest\application.properties

打包把springboottest-0.0.1-SNAPSHOT.jar放在D:\,jdk所在的目录:C:\Program Files\Java\jdk17.0.8\bin,切换到jdk所在的目录执行如下命令:java -jar d:\springboottest-0.0.1-SNAPSHOT.jar,得到的输出结果如下:

复制代码
=========小游戏 地心侠士 ResourceUtils类默认路径=========
ResourceUtils ""   路径: C:\Program Files\Java\jdk17.0.8\bin
ResourceUtils "."  路径: C:\Program Files\Java\jdk17.0.8\bin
ResourceUtils "./" 路径: C:\Program Files\Java\jdk17.0.8\bin
ResourceUtils "../"路径: C:\Program Files\Java\jdk17.0.8
ResourceUtils "/" 路径: C:\
ResourceUtils  classpath: 路径: class path resource [application.properties] cannot be resolved to absolute file path because it does not reside in the file system: jar:nested:/D:/springboottest-0.0.1-SNAPSHOT.jar/!BOOT-INF/classes/!/application.properties
ResourceUtils file: 路径: C:\Program Files\Java\jdk17.0.8\bin\application.properties

切换到jar所在目录执行如下命令:"C:\Program Files\Java\jdk17.0.8\bin\java.exe" -jar springboottest-0.0.1-SNAPSHOT.jar

得到的输出结果如下:

复制代码
=========小游戏 地心侠士 ResourceUtils类默认路径=========
ResourceUtils ""   路径: D:\
ResourceUtils "."  路径: D:\
ResourceUtils "./" 路径: D:\
ResourceUtils "../"路径: D:\
ResourceUtils "/" 路径: D:\
ResourceUtils  classpath: 路径: class path resource [application.properties] cannot be resolved to absolute file path because it does not reside in the file system: jar:nested:/D:/springboottest-0.0.1-SNAPSHOT.jar/!BOOT-INF/classes/!/application.properties
ResourceUtils file: 路径: D:\application.properties

通过ResourceUtils测试,总结如下:

  • 不同场景下运行程序得到到的默认路径同File保持一致特性.同工作目录强相关.
  • 使用Springclasspath前缀获取文件时,默认从运行的jar包查找
  • 使用Springfile前缀获取文件时,默认从当前根目录查找

7. 总结

  • ResourceUtilsFile 类使用路径获取资源时,是以工作目录为参考
  • class.getResource 方法使用路径参数获取资源时,是以这个类的位置为参考
  • classLoader.getResource正常情况下以classpth目录为基准,不支持路径参数不支持绝对路径.并且java9使用模块化机制,影响很大
  • 不管那种方式"",".","./"都表示当前目录

SpringBoot中提供了很多有用的类,合理使用,绝对事半功倍.不知道各位javaer们都经常使用哪些内置类

相关推荐
葫芦和十三5 小时前
图解 MongoDB 21|选举与 failover:Primary 是怎么选出来的
后端·mongodb·agent
GetcharZp6 小时前
26k Star 开源内网穿透神器 NetBird,一分钟实现全球设备互联!
后端
考虑考虑6 小时前
Mybatis实现批量插入
java·后端·mybatis
咖啡八杯7 小时前
GoF设计模式——中介者模式
java·后端·spring·设计模式
lizhongxuan9 小时前
多Agent之间的区别
后端
青石路11 小时前
记一次多JDK版本问题的排查,一坑套一坑,差点没爬上来
java
杨充11 小时前
1.面向对象设计思想
后端
IT_陈寒12 小时前
Java的Date类又坑了我一次,改用时间戳真香
前端·人工智能·后端
systemPro12 小时前
2.6亿条设备数据,历史查询从超时到50ms,我做了什么
后端
要阿尔卑斯吗12 小时前
提示词优化启示:为什么“按顺序输出“比“关键度评分“更有效
后端