ClassLoader.getResourceAsStream是如何工作的?
我已经用Maven创建了一个JAR文件。当我打开这个罐子时,我可以找到以下内容:
my.jar
|_text1.txt
|_folder
|_ ... some other stuff
当我在Eclipse中运行此代码片段时,";ext1.txt";的内容以及输出的文件夹内容中的所有文件名
String tmp = IOUtils.toString(App.class.getClassLoader().getResourceAsStream("text1.txt"), StandardCharsets.UTF_8);
System.err.println(tmp);
tmp = IOUtils.toString(App.class.getClassLoader().getResourceAsStream("folder"), StandardCharsets.UTF_8);
System.err.println(tmp);
当我将此代码作为独立程序运行时,也将打印来自";ext1.txt";的内容,但文件夹的第二部分返回空。
我做错了什么?
解决方案
App.class.getClassLoader().getResourceAsStream
不要这样做。正确的方式是App.class.getResourceAsStream
。有些时候getCLassLoader()
返回NULL;在这种情况下,您的策略失败了,上面的方法可以很好地工作。此外,您的方式是更多的调用和更多的代码,而不会获得任何好处。
IOUtils.toString(App.class.getClassLoader().getResourceAsStream("folder")
您无法获取"文件夹"。你觉得这会有什么用呢?设计到资源加载器系统中的抽象(这就是您在这里使用的)不允许您以任何方式获取文件夹,也不允许您列出文件夹的内容。(您可能正在寻找SPI:服务提供商接口)。
IOUtils
您不需要这个;java.nio.file.Files
是内置的,并且同样有一个toString方法。它甚至默认为UTF-8
,因此您不必指定它。
App.class.getResourceAsStream("text1.txt")
这将在与App.class完全相同的位置查找t1.txt。甚至是相同的包装结构。如果您想从App.class所在位置的"根"开始(因此,通常是-classpath
上的内容),请在前面加一个斜杠:例如,请求"/text1.txt"
。
假设您的ext1.txt位于根目录中,而不是com/foo/pkg/MyApp.class
旁边的com/foo/pkg
中,则需要指定"/text1.txt"
才能找到它。
如果您不确定此内容的位置,请输出此调用的结果:
App.class.getResource("App.class");
这会打印一个URL,您的眼球将能够从它看到它的位置。
和打印出的文件夹内容中的所有文件名
那很好。这不起作用--eclipse在运行时为您提供了这是一种怪异,但规范基本上没有对此进行抽象。ClassLoader实现可以做他们想做的任何事情(这是一个可插拔的系统),它们需要实现的唯一方法是"在这个位置找到资源"。如果您请求一个‘文件夹’,则没有义务返回文件名字符串,而且大多数类加载器(包括读取JAR文件的类加载器)根本不需要这样做。
解决方案是SPI:在编译时创建一个列出路径或类名的文件,然后在运行时使用资源系统加载该文件,然后加载其中列出的每个类/每个资源。作为编译的一部分,注释处理器可以自动生成此文件的过程,从而使整个测试过程无缝进行。在Web上搜索SPI Java以了解更多信息。
相关文章