读取作为资源在运行时创建的文件时找不到文件



此行返回null,因为它找不到文件:

inputStream = getClass().getClassLoader().getResourceAsStream(filename);

filesrc/test/resources/test.tmp

file是这样写的:

Files.write(Paths.get(file.getAbsolutePath()), "test".getBytes(StandardCharsets.UTF_8));

如果我在运行应用程序之前创建了file,那么它就可以工作,但如果我在执行时(如在单元测试中(创建file,那么inputStream将返回为null,因为找不到file

如何在运行时创建一个可以作为Stream从resources目录读取的文件?

getResourceAsStream系统从根本上;做";写。该方法将从系统加载类的任何位置检索资源,并且不能保证"where ever"可能支持编写的概念。事实上,它可能来自的所有可用位置都不支持它。除了从"原始"类文件运行。这种情况通常只在开发过程中发生,因此,这是一种毫无意义的做法。

因此,您编写的代码不起作用,也无法使其起作用。如果要写入数据,则getResourceAsStream不能参与该过程。

更普遍地说,代码位于你无法写入的位置。或者,应该是-一些穷乡僻壤的操作系统有疯狂的糟糕安全默认值,并允许你这样做。这只是意味着所说的操作系统很糟糕,而不是说你应该在它们之后立即运行。因此,应该避免任何黑客行为(当然是可用的,但很脆弱,因为它需要java无法保证的某些类路径设置(——你最终得到的只是一个不能写入或不应该写入的目录。

存储数据的正确位置是..而不是"罐子旁边/里面"。它位于用户的主目录、"Documents"目录或用户配置的某个位置。

您可以使用Paths.get(System.getProperty("user.home"))访问用户的主目录。

附录:使用getResourceAsStream进行测试

如果您想为了测试目的修改某个gRAS调用返回的内容,您有几个广泛的选项。

最佳选择:测试资源

gRAS可以从类路径上的任何位置读取,在测试运行期间,您的测试内容就在那里1。因此,您真正需要的只是将传递给gRAS的字符串参数化,这样测试运行就可以在那里使用不同的字符串。然后,将测试数据存储在那里。如果你需要动态生成这些东西,在你的测试源代码中有一个单独的小应用程序来制作它,然后把它放在通常的src/test/resources中(并签入(。测试中的随机性很烦人,如果没有充分的理由,就不要添加它。

备选方案1:嘲笑它

我不太熟悉这些技术,但有些人似乎真的很喜欢它:你可以用模拟库模拟系统的各个部分,因此,你可以模拟gRAS返回的内容,并返回自定义InputStreams,例如用创建的

String testData = "Here is my test data I just generated";
return new ByteArrayInputStream(testData.getBytes(StandardCharsets.UTF_8));

备选方案2:Classloader

您可以编写自己的ClassLoader,并在系统要求您提供资源时根据自己的意愿进行响应。这就是的要点:如果你想编写一个java应用程序,其中类不是从jar文件加载的,而是通过网络加载的,你可以通过编写自己的ClassLoader来做到这一点。您甚至可以动态生成类文件,或者使用现有的类文件,并使用字节码自省库(如ASM或BCEL等(对其进行修改/com/foo/data.txt";,只需返回这些数据,而不是该资源的实际内容。

这有点复杂——从阅读ClassLoader的javadoc开始,在网上搜索一些例子和教程,应该会有很多。不过,这感觉有点像是一个沉重的问题解决方案。然而,它最准确地回答了一个问题:;我想动态生成getResourceAsStream从我自己的代码中返回的内容;。

[1] 通常。gRAS调用可以归结为"类加载器",并且有一些特殊的测试设置将测试内容粘贴在与主应用程序内容分离的类加载器中,在这种情况下,gRAS将无法再找到它。这种练习的主要目的是确保没有应用程序代码实际使用测试代码中的任何内容,因为关键是在生产过程中根本不存在测试代码(但如何使用模块化类加载器进行测试(。然而,据我所知,TestNG和JUnit都没有开箱即用。所以你应该没事的。

最新更新