写了个读配置的小工具,在IDEA里跑得好好的,打包成jar放到服务器上就报文件找不到。问题出在拿路径的方式上,工作目录和类路径根本不是一回事。这几种取法各有适用范围,混着用最容易出坑。
user.dir 拿到的是启动目录
System.getProperty传user.dir这个属性名,返回的是JVM启动时的工作目录,也就是敲java命令时所在的文件夹,不是class文件所在处。用java -jar启动时,它是命令行当前路径;被计划任务以别的目录拉起时,它可能变成系统盘根目录。所以用相对路径去找同级目录里的文件,十有八九会错。
Paths.get 与 File 的组合
用Paths.get接一个文件名再调toAbsolutePath,会基于user.dir拼出完整路径,本质还是相对启动目录。想拼路径别用字符串加斜杠,用Paths.get传父目录和文件名两段,它能自动处理Windows的反斜杠和Linux的正斜杠。判断目录是否存在用Files.exists,比new File().exists()清楚。
Path base = Paths.get(System.getProperty(「user.dir」)); Path cfg = base.resolve(「conf」).resolve(「app.yml」);类加载器资源路径才是打jar后的正解
配置文件打进jar里以后,它在文件系统里没有独立路径,Paths.get必然失败。要用类加载器读流:getClass().getClassLoader().getResourceAsStream(「app.yml」)。资源放在src/main/resources下,打包后就在jar根目录。注意别用getResource拿URL再转File,jar内资源转File同样会抛FileNotFoundException。
几个容易踩的细节
- 中文目录:路径含空格或中文时,别自己拼命令行,走ProcessBuilder传参。
- 可写目录:jar所在目录不一定可写,生成日志要写到user.home或指定的数据目录。
- Web环境:war包里用ServletContext的getRealPath,但打成fat jar后这个方法返回null。
一句话判断:读随程序分发的只读文件,用类加载器流;读运行目录的配置,用user.dir加Paths,并且把这个目录固定成启动脚本里的绝对路径,别依赖用户在哪里敲命令。