提问人:Koi 提问时间:12/5/2013 最后编辑:NM NaufaldoKoi 更新时间:9/5/2022 访问量:482195
从 jar 中读取资源文件
Reading a resource file from within jar
问:
我想从我的罐子里读取一个资源,如下所示:
File file;
file = new File(getClass().getResource("/file.txt").toURI());
BufferedReader reader = new BufferedReader(new FileReader(file));
//Read the file
在 Eclipse 中运行它时它工作正常,但是如果我将其导出到 jar 中,然后运行它,则会出现 IllegalArgumentException:
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,并且包含我的文件的文件夹位于 class 文件夹中。
答:
与其尝试将资源作为文件进行寻址,不如让 ClassLoader 返回资源的 InputStream,而是通过 getResourceAsStream:
try (InputStream in = getClass().getResourceAsStream("/file.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
// Use resource
}
只要资源在类路径上可用,那么无论资源是在目录中还是在目录中,此方法都将以相同的方式工作。file.txt
file.txt
classes/
jar
发生这种情况是因为 jar 文件中资源的 URI 将如下所示:.您不能像读取普通旧文件一样读取(文件)中的条目。URI is not hierarchical
file:/example.jar!/file.txt
jar
zip
以下答案很好地解释了这一点:
评论
InputStream
File.exists()
getClass().getResource("**/folder**/file.txt")
getResourceAsStream
如果资源不存在,则返回 null,以便可以作为“存在”测试。
You cannot read the entries within a jar (a zip file) like it was a plain old File.
这很糟糕,因为有大量的库函数需要文件路径作为输入。
如果你想作为一个文件阅读,我相信仍然有一个类似的解决方案:
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("file/test.xml").getFile());
评论
file:
要访问 jar 中的文件,您有两种选择:
将文件放在与您的包名称匹配的目录结构中(提取 .jar 文件后,它应该与 .class 文件位于同一目录中),然后使用
getClass().getResourceAsStream("file.txt")
将文件放在根目录下(提取 .jar 文件后,它应该在根目录下),然后使用
Thread.currentThread().getContextClassLoader().getResourceAsStream("file.txt")
当 jar 用作插件时,第一个选项可能不起作用。
评论
确保使用正确的分隔符。我用 .这在 IDE 中工作正常,但在构建 JAR 中不起作用。/
File.separator
如果你使用的是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();
}
评论
我以前遇到过这个问题,我做了加载的后备方式。基本上,第一种方式在 .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;
}
}
评论
到目前为止(2017 年 12 月),这是我发现的唯一一个在 IDE 内部和外部都有效的解决方案。
使用 PathMatchingResourcePatternResolver
注意:它也适用于spring-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);
}
您可以使用类加载器,它将从类路径读取为 ROOT 路径(开头不带“/”)
InputStream in = getClass().getClassLoader().getResourceAsStream("file.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
出于某种原因,当我将 Web 应用程序部署到 WildFly 14 时,总是返回 null。获取 classLoader from 或返回 null。classLoader.getResource()
getClass().getClassLoader()
Thread.currentThread().getContextClassLoader()
getClass().getClassLoader()
API doc 说道,
“返回类的类加载器。某些实现可能使用 null 来表示引导类加载器。如果此类是由引导类加载器加载的,则此方法将在此类实现中返回 null。
如果您使用的是 WildFly 和您的 Web 应用程序,请尝试一下
request.getServletContext().getResource()
返回资源 URL。这里 request 是 ServletRequest 的对象。
问题在于某些第三方库需要文件路径名而不是输入流。大多数答案都没有解决这个问题。
在这种情况下,一种解决方法是将资源内容复制到临时文件中。以下示例使用 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();
}
评论
resourceName
/
File
decomposePath
path.split("/")
.toArray(new String[0]))
folder
Lists
REPLACE_EXISTING
以下代码适用于 Spring boot(kotlin):
val authReader = InputStreamReader(javaClass.getResourceAsStream("/file1.json"))
我找到了解决方法
BufferedReader br = new BufferedReader(new InputStreamReader(Main.class.getResourceAsStream(path)));
将“Main”替换为您编写代码的 java 类。将“path”替换为 jar 文件中的路径。
例如,如果将 State1.txt 放在包 com.issac.state 中,则如果运行 Linux 或 Mac,则键入路径为“/com/issac/state/State1”。如果运行 Windows,则键入路径为“\com\issac\state\State1”。不要将 .txt 扩展名添加到文件,除非发生“找不到文件”异常。
此代码适用于 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
就我而言,我终于做到了
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
评论
getClass().getClassLoader().getResourceAsStream()
最后我解决了错误:
String input_path = "resources\\file.txt";
input_path = input_path.replace("\\", "/"); // doesn't work with back slash
URL file_url = getClass().getClassLoader().getResource(input_path);
String file_path = new URI(file_url.toString().replace(" ","%20")).getSchemeSpecificPart();
InputStream file_inputStream = file_url.openStream();
评论
getResourceAsStream