ClassLoader中的getResource/getResourceStream是我们最常用的加载资源文件的工具(关于ClassLoader路径的困惑,可以把他理解成,是以Jar文件所在目录为当前目录或根目录; 有别于 File: /(系统根目录) or ./(当前执行目录));
好久没具体写加载资源的代码,今天一写就遇到一个问题;
书写代码如下:
Path p = Paths.get(Test.class.getClassLoader().getResource("resource/hello.txt").toURI());
Files.readAllLines(p).forEach(a -> System.out.println(a.toString()));
resource是放在当前项目build路径根目录下的一个资源文件夹; 上述代码在eclipse中一切运行正常, 但是export成jar以后, 再执行就回抛出错误;
分析:
eclipse下build path里是以普通文件和文件夹形式存在, 而打包成jar以后,它实际上是一整个文件;
使用getResource.toURI打印出来对比一下;
//在eclipse中;
file:/F:/src2020/classpathTest/bin/resource/hello.txt
//在jar中;
jar:file:/F:/src2020/shotool/sho.jar!/resource/hello.txt
可以看到在jar中的协议不是普通的文件协议;
综合上面所述,打包成jar以后返回得URI并不是file:/协议;因而用Paths.get, File去解析URI都无法得到正确的结果; 也就是再打包成jar以后,不应该再把resource和里面的文件当作普通单独的文件和文件夹对待
解决办法, 使用getResourceStream, 看过Stream的代码,恰当的基于协议将文件转化成流;
//还是不得不直接操作Stream;
try(InputStream input = Test.class.getClassLoader().getResourceAsStream("resource/hello.txt");) {
String result = new BufferedReader(new InputStreamReader(input))
.lines().collect(Collectors.joining(System.lineSeparator()));
System.out.println(result);
} catch (Exception e) {
// TODO: handle exception
}