File file;
file = new File(getClass().getResource("/file.txt").toURI());
BufferedReader reader = new BufferedReader(new FileReader(file));
//Read the file
,当在Eclipse中运行它时,它可以正常工作,但是如果我将其导出到jar中,则可以运行IllegalArgumentException: br />
Exception in thread "Thread-2"
java.lang.IllegalArgumentException: URI is not hierarchical
,我真的不知道为什么,但是通过一些测试,我发现是否可以将
file = new File(getClass().getResource("/file.txt").toURI());
更改为
file = new File(getClass().getResource("/folder/file.txt").toURI());
,那么它的作用相反(它可以在jar中使用,但不能用于Eclipse。)
我正在使用Eclipse,并且带有我的文件的文件夹位于类文件夹中。
#1 楼
而不是尝试将资源作为文件寻址,只需让ClassLoader通过getResourceAsStream返回资源的InputStream即可:InputStream in = getClass().getResourceAsStream("/file.txt"); BufferedReader reader = new BufferedReader(new InputStreamReader(in));
pre >
只要file.txt
资源在类路径上可用,那么无论file.txt
资源位于classes/
目录中还是位于jar
内部,此方法都将以相同的方式工作。
之所以发生URI is not hierarchical
,是因为jar文件中资源的URI看起来像这样:file:/example.jar!/file.txt
。您无法读取jar
(zip
文件)中的条目,就像它是一个普通的旧文件一样。
以下答案可以很好地解释这一点:
如何从Java jar文件读取资源文件?
Java Jar文件:使用资源错误:URI不是分层的
评论
谢谢您,这非常有帮助并且代码可以完美地工作,但是我确实有一个问题,我需要确定InputStream是否存在(例如File.exists()),以便我的游戏可以判断是否使用默认文件。谢谢。
– PrinceCJC
2013年12月5日15:23
哦,顺便说一句,getClass()。getResource(“ ** / folder ** / file.txt”)起作用的原因是因为我将该文件夹放在jar的同一目录中:)。
– PrinceCJC
2013年12月5日15:33
如果资源不存在,则getResourceAsStream返回null,这可以成为您的“存在”测试。
–提请MacInnis
2013年12月5日19:05
当然...不要忘记关闭inputStream和BufferedReader
– Noremac
15年5月15日在13:38
我这样做了,然后将声音文件放在NetBeansProjects \ Test \ build \ classes路径中,但是使用clean和build将从该路径中清除。并且通过转换为exe,它不再有权访问声音文件。我的问题在哪里?
–巴黎
18 Mar 12 '18 at 19:05
#2 楼
要访问jar中的文件,您有两个选择:将文件放入与您的包名称匹配的目录结构中(提取.jar文件后,该文件应与相同的目录。类文件),然后使用
getClass().getResourceAsStream("file.txt")
访问它。将文件放在根目录(提取.jar文件后,它应该在根目录中),然后使用
Thread.currentThread().getContextClassLoader().getResourceAsStream("file.txt")
访问它。将jar用作插件时可能无法工作。
评论
非常感谢您提供了一个很好的答案...第二个选项的另一个好处是它也可以在main方法中使用,因为getClass()仅在实例中有效,而在静态方法中无效。
–丹·奥尔特加(Dan Ortega)
2月5日20:43
#3 楼
我之前有这个问题,所以我做了后备的加载方式。基本上,第一种方法在.jar文件中工作,第二种方法在eclipse或其他IDE中工作。public class MyClass {
public static InputStream accessFile() {
String resource = "my-file-located-in-resources.txt";
// this is the path within the jar file
InputStream input = MyClass.class.getResourceAsStream("/resources/" + resource);
if (input == null) {
// this is how we load file within editor (eg eclipse)
input = MyClass.class.getClassLoader().getResourceAsStream(resource);
}
return input;
}
}
#4 楼
到目前为止(2017年12月),这是我发现的唯一可在IDE内部和外部使用的解决方案。使用PathMatchingResourcePatternResolver
注意:它在春季也可以工作, boot
在此示例中,我正在读取src / main / resources / my_folder中的一些文件:
try {
// Get all the files under this inner resource folder: my_folder
String scannedPackage = "my_folder/*";
PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver();
Resource[] resources = scanner.getResources(scannedPackage);
if (resources == null || resources.length == 0)
log.warn("Warning: could not find any resources in this scanned package: " + scannedPackage);
else {
for (Resource resource : resources) {
log.info(resource.getFilename());
// Read the file content (I used BufferedReader, but there are other solutions for that):
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
// ...
// ...
}
bufferedReader.close();
}
}
} catch (Exception e) {
throw new Exception("Failed to read the resources folder: " + e.getMessage(), e);
}
#5 楼
问题在于某些第三方库需要文件路径名而不是输入流。大多数答案都不能解决这个问题。在这种情况下,一种解决方法是将资源内容复制到一个临时文件中。以下示例使用jUnit的TemporaryFolder
。 private List<String> decomposePath(String path){
List<String> reversed = Lists.newArrayList();
File currFile = new File(path);
while(currFile != null){
reversed.add(currFile.getName());
currFile = currFile.getParentFile();
}
return Lists.reverse(reversed);
}
private String writeResourceToFile(String resourceName) throws IOException {
ClassLoader loader = getClass().getClassLoader();
InputStream configStream = loader.getResourceAsStream(resourceName);
List<String> pathComponents = decomposePath(resourceName);
folder.newFolder(pathComponents.subList(0, pathComponents.size() - 1).toArray(new String[0]));
File tmpFile = folder.newFile(resourceName);
Files.copy(configStream, tmpFile.toPath(), REPLACE_EXISTING);
return tmpFile.getAbsolutePath();
}
评论
这被掩盖了很多。感谢您记录它。我很好奇,如果没有JUnit,还有哪些其他选择。
– Alex Moore-Niemi
3月9日21:07
由于resourceName应该始终使用/作为分隔符,与decomposePath内部的File操作使用系统特定的文件分隔符不同,该方法不仅与path.split(“ /”)相比不必要地复杂,而且甚至是不正确的。此外,不清楚为什么不使用它的结果时调用.toArray(new String [0]))。
–霍尔格
8月26日8:22
什么是文件夹,什么是列表库,什么是REPLACE_EXISTING ...?请提供有关您帖子的完整信息。
– ElectroRocnic
10月1日14:01
#6 楼
就我而言,我终于用import java.lang.Thread;
import java.io.BufferedReader;
import java.io.InputStreamReader;
final BufferedReader in = new BufferedReader(new InputStreamReader(
Thread.currentThread().getContextClassLoader().getResourceAsStream("file.txt"))
); // no initial slash in file.txt
做到了
评论
奇怪的是,对于我来说,这也是嵌套资源的解决方案。我不知道为什么它似乎可以与其他已发布答案中的斜杠一起使用。
– ElectroRocnic
10月1日19:51
@ElectRocnic我认为是因为如何解释路径。 “ /file.txt”说,切换到当前目录并打开file.txt,而“ file.txt”说,从当前位置打开file.txt。它们都指向同一位置。对我来说,两者都可以在Windows系统中使用。
– srishti sharma
10月7日5:02
啊哈,它在docker + linux环境中对我不起作用...感谢您的发言
– ElectroRocnic
10月7日9:49
#7 楼
我找到了一个修复程序BufferedReader br = new BufferedReader(new InputStreamReader(Main.class.getResourceAsStream(path)));
将“ Main”替换为您在其中编写的Java类。用jar文件中的路径替换“ path”。
,例如,如果将State1.txt放入com.issac.state包中,那么如果运行Linux或Mac,则将路径键入为“ / com / issac / state / State1”。如果运行Windows,则将路径键入为“ \ com \ issac \ state \ State1”。除非发生“找不到文件”异常,否则请勿将.txt扩展名添加到文件中。
#8 楼
确保使用正确的分隔符。我用/
替换了相对路径中的所有File.separator
。这在IDE中工作正常,但是在构建JAR中不起作用。#9 楼
我认为这也应该在Java中工作。我使用的以下代码正在使用kotlin。val resource = Thread.currentThread().contextClassLoader.getResource('resources.txt')
#10 楼
该代码在Eclipse和Exported Runnable JAR中均有效。private String writeResourceToFile(String resourceName) throws IOException {
File outFile = new File(certPath + File.separator + resourceName);
if (outFile.isFile())
return outFile.getAbsolutePath();
InputStream resourceStream = null;
// Java: In caso di JAR dentro il JAR applicativo
URLClassLoader urlClassLoader = (URLClassLoader)Cypher.class.getClassLoader();
URL url = urlClassLoader.findResource(resourceName);
if (url != null) {
URLConnection conn = url.openConnection();
if (conn != null) {
resourceStream = conn.getInputStream();
}
}
if (resourceStream != null) {
Files.copy(resourceStream, outFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
return outFile.getAbsolutePath();
} else {
System.out.println("Embedded Resource " + resourceName + " not found.");
}
return "";
}
评论
certPath在这里是什么?
–汤姆·泰勒(Tom Taylor)
11月18日8:13
#11 楼
您可以使用类加载器,该类加载器将从类路径中读取作为ROOT路径(开头不带“ /”)InputStream in = getClass().getClassLoader().getResourceAsStream("file.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
#12 楼
由于某些原因,当我将Web应用程序部署到WildFly 14时,classLoader.getResource()
总是返回null。从getClass().getClassLoader()
或Thread.currentThread().getContextClassLoader()
获取classLoader返回null。该类的类加载器。某些实现可能使用null来表示引导类加载器。如果此类是由引导类加载器加载的,则该方法在此类实现中将返回null。“
正在使用WildFly,并且您的Web应用程序尝试使用此方法
getClass().getClassLoader()
返回了资源URL。这里的请求是ServletRequest的对象。#13 楼
如果您想阅读为文件,我相信仍然有类似的解决方案: ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("file/test.xml").getFile());
评论
URL.getFile()不会将URL转换为文件名。它返回主机之后的URL部分,并完整保留所有百分比编码,因此,如果路径包含任何非ASCII字符或URL中不允许的任何ASCII字符(包括空格),则结果将不是现有文件名,即使该URL是文件:URL。
– VGR
16年5月5日在18:07
一旦将程序构建到jar中,这将无法在内部运行
– Akshay Kasar
17年9月20日在12:42
除非您转换为字符串并将其首先保存在本地,否则无法从jar中使用。
–smoosh911
18年8月9日在16:55
#14 楼
如果您使用的是spring,则可以使用以下方法从src / main / resources中读取文件:import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.springframework.core.io.ClassPathResource;
public String readFileToString(String path) throws IOException {
StringBuilder resultBuilder = new StringBuilder("");
ClassPathResource resource = new ClassPathResource(path);
try (
InputStream inputStream = resource.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
resultBuilder.append(line);
}
}
return resultBuilder.toString();
}
评论
欢迎来到SO。这不能为问题提供答案。拥有足够的声誉后,您就可以在任何帖子中发表评论。还要检查一下该怎么办。
–前进的道路
17年5月3日在15:36
这将删除文件中的换行符!
–elad.chen
19 Mar 3 '19 at 9:44
#15 楼
以下代码适用于Spring Boot(kotlin):val authReader = InputStreamReader(javaClass.getResourceAsStream("/file1.json"))
评论
如果要从jar中的目录中读取文件,其中包含文件的任何编号,请参见Stackoverflow-Link我不确定原始问题是否涉及Spring。上一条评论中的链接引用了来自其他问题的特定于Spring的答案。我相信getResourceAsStream仍然是解决此问题的更简单,更可移植的解决方案。