打包部署后无法读取jar包里的文件(实测可行,Java中读取jar包中的文件)

您所在的位置:网站首页 jar英语怎么写 打包部署后无法读取jar包里的文件(实测可行,Java中读取jar包中的文件)

打包部署后无法读取jar包里的文件(实测可行,Java中读取jar包中的文件)

2023-06-27 05:43| 来源: 网络整理| 查看: 265

打包部署后无法读取jar包里的文件 Java中读取jar包中的文件 linux中无法读取jar包中的内容(windows可以的!),如何解决

一、背景

项目中免不了需要读取文件,如果文件用绝对路径读取,就需要配置或写死路径,非常不便。如果我们读取类路径上的文件,就不会这么麻烦。

比如要读取的文件位于类路径下 java/main/resources/myfile.txt,这个文件在项目打成jar包的时候,也会压缩在里头,非常方便。

用 this.getClass().getResource(resourcePath) 或 this.getClass().getResourceAsStream(resourcePath) 获得文件路径或输入流。

上面2个方法就是从类路径上读取文件的,但有个大坑,就是你在IDEA里调试得好好的,但打成jar包,启动项目后发现可能会无法读取到这个文件。详细如下

打成jar包在linux启动,但是读取输入流为null

打成jar包在windows启动,能读取到输入流 (很奇葩,linux不能windows居然能)

在 IDEA 里:能读取到这个输入流

怎么解决 我实际验证了,下面的方式可行。

二、如何解决

改成读取jar包的方式读取jar包内的文件

如下这个类,就可以读取到输入流。。

JarFile 等是JDK自带的两个参数,第一个是jar包的位置,第二个是要读取的文件在jar包内的路径 public static InputStream readInputStreamFromJar(String jarPath, String fileInJar) { JarFile jarFile = null; InputStream input = null; try { jarFile = new JarFile(jarPath); JarEntry jarEntry = jarFile.getJarEntry(fileInJar); input = jarFile.getInputStream(jarEntry); return input; } catch (IOException e) { throw new RuntimeException(e); } finally { // 千万别关闭 jarFile,即使在这里没有关闭 inputStream,但是关闭 jarFile相当于关闭了 inputStream, // 会导致 inputStream 虽然不是null但是available=0即没有内容了!!! // IOUtils.closeQuietly(jarFile); } }

上述接口如何传参?

按下面的方法获得需要的入参

JarPathResult 不列出代码了,就是个装返回结果的类 private static JarPathResult getJarResult(String path) { int firstMark = path.indexOf("!"); int length = "jar:file:".length(); String jarFile = path.substring(length, firstMark);// 截出来win是/D:/... ,但后续仍然正常运行 String fileInJar = path.substring(firstMark + "!/".length()).replace("!", "");// 去掉开头的!/开头 JarPathResult result = new JarPathResult(); result.setJarFile(jarFile); result.setFileInJar(fileInJar); return result; }

getJarResult(path)的入参说明

入参说明: 传入类似下面的格式的路径 jar:file:/root/app/read-file-from-jar-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/sub/subfile.txt (即传入 `this.getClass().getResource("/sub/subfile.txt").toString()` 的值) 出参说明: /root/app/read-file-from-jar-0.0.1-SNAPSHOT.jar BOOT-INF/classes/sub/subfile.txt

补充:

对于 this.getClass().getResource("/sub/subfile.txt").toString()

**怎么知道要写成 /sub/subfile.txt ? **

你的文件放在 java/main/resources 下的,以这个为根路径,以/开头,定位到你的文件。

比如 java/main/resources/abc.txt 就写成 /abc.txt又如 java/main/resources/aa/bb/abc.txt 就写成 /aa/bb/abc.txt。

注意:

如果你乱写一个文件不存在或者路径写错,就会导致 getResource 返回null,toString之前是最好判断非null的在 IDEA 里跑会报错,因为IDEA 里获取的路径不是 jar:file:/ 开头的!!!可以判断一些,如果是 jar:file:/ 开头的用JAR包的方式读取,如果是 file:/ 开头,直接用 this.getClass().getResourceAsStream() 即可。 附录:关于 getResource 读取的路径

this.getClass().getResource(resourcePath) 返回URL,这个URL#toString() 后就得到一个路径

有以下文件,分别放在:

src/main/resources/myfile.txt src/main/resources/sub/myfile.txt

设计了如下的代码,在IDEA里启动项目后请求接口。之后再打jar包,并分别在windows、linux中启动

@GetMapping("/getPath") public Map getPath() { Map map = new HashMap(); String resourcePath1 = "/myfile.txt"; String resourcePath2 = "/sub/subfile.txt"; URL filepathUrl1 = this.getClass().getResource(resourcePath1); URL filepathUrl2 = this.getClass().getResource(resourcePath2); String filepath1 = filepathUrl1 == null ? null : filepathUrl1.toString(); String filepath2 = filepathUrl2 == null ? null : filepathUrl2.toString(); map.put(resourcePath1 + " 的绝对路径是:", filepath1); map.put(resourcePath2 + " 的绝对路径是:", filepath2); return map; }

读取的结果是:

可以自行观察路径的规律。

在IDEA 里运行:

file:/D:/DevFolder/code/hello/read-file-from-jar/target/classes/myfile.txt

file:/D:/DevFolder/code/hello/read-file-from-jar/target/classes/sub/subfile.txt

打包后再win里运行:

jar:file:/D:/DevFolder/code/hello/read-file-from-jar/target/read-file-from-jar-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/myfile.txt

jar:file:/D:/DevFolder/code/hello/read-file-from-jar/target/read-file-from-jar-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/sub/subfile.txt

打包后再linux里运行:

jar:file:/root/app/read-file-from-jar-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/myfile.txt

jar:file:/root/app/read-file-from-jar-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/sub/subfile.txt

总结:

直接在 IDEA 中运行,会得到 file:/...打成jar包后运行,得到 jar:file:/...jar:file:/... 的格式有两个 ! 号,信息被分成了3段 第一段是jar包的位置,比如 /root/app/read-file-from-jar-0.0.1-SNAPSHOT.jar第二段是classpath的路径,比如 /BOOT-INF/classes第三段是文件真正在什么路径,比如 /myfile.txt 或者 /sub/subfile.txt


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3