如何从Java中的jar读取文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3369794/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to read a file from jar in Java?
提问by kandarp
I want to read an XML file that is located inside one of the jar
s included in my class path. How can I read any file which is included in the jar
?
我想读取位于jar
我的类路径中包含的s之一内的 XML 文件。如何读取包含在jar
.
回答by Mnementh
If you want to read that file from inside your application use:
如果您想从应用程序内部读取该文件,请使用:
InputStream input = getClass().getResourceAsStream("/classpath/to/my/file");
The path starts with "/", but that is not the path in your file-system, but in your classpath. So if your file is at the classpath "org.xml" and is called myxml.xml your path looks like "/org/xml/myxml.xml".
路径以“/”开头,但这不是文件系统中的路径,而是类路径中的路径。因此,如果您的文件位于类路径“org.xml”并且名为 myxml.xml,则您的路径看起来像“/org/xml/myxml.xml”。
The InputStream reads the content of your file. You can wrap it into an Reader, if you want.
InputStream 读取文件的内容。如果需要,您可以将其包装到 Reader 中。
I hope that helps.
我希望这有帮助。
回答by simontuffs
Ah, this is one of my favorite subjects. There are essentially two ways you can load a resource through the classpath:
啊,这是我最喜欢的科目之一。基本上有两种方法可以通过类路径加载资源:
Class.getResourceAsStream(resource)
and
和
ClassLoader.getResourceAsStream(resource)
(there are other ways which involve getting a URL for the resource in a similar fashion, then opening a connection to it, but these are the two direct ways).
(还有其他方法涉及以类似方式获取资源的 URL,然后打开与它的连接,但这是两种直接方式)。
The first method actually delegates to the second, after mangling the resource name. There are essentially two kinds of resource names: absolute (e.g. "/path/to/resource/resource") and relative (e.g. "resource"). Absolute paths start with "/".
在修改资源名称之后,第一种方法实际上委托给第二种方法。基本上有两种资源名称:绝对(例如“/path/to/resource/resource”)和相对(例如“资源”)。绝对路径以“/”开头。
Here's an example which should illustrate. Consider a class com.example.A. Consider two resources, one located at /com/example/nested, the other at /top, in the classpath. The following program shows nine possible ways to access the two resources:
这是一个应该说明的例子。考虑一个类 com.example.A。考虑两个资源,一个位于类路径中的 /com/example/nested,另一个位于 /top。以下程序显示了访问这两种资源的九种可能方式:
package com.example; public class A { public static void main(String args[]) { // Class.getResourceAsStream Object resource = A.class.getResourceAsStream("nested"); System.out.println("1: A.class nested=" + resource); resource = A.class.getResourceAsStream("/com/example/nested"); System.out.println("2: A.class /com/example/nested=" + resource); resource = A.class.getResourceAsStream("top"); System.out.println("3: A.class top=" + resource); resource = A.class.getResourceAsStream("/top"); System.out.println("4: A.class /top=" + resource); // ClassLoader.getResourceAsStream ClassLoader cl = A.class.getClassLoader(); resource = cl.getResourceAsStream("nested"); System.out.println("5: cl nested=" + resource); resource = cl.getResourceAsStream("/com/example/nested"); System.out.println("6: cl /com/example/nested=" + resource); resource = cl.getResourceAsStream("com/example/nested"); System.out.println("7: cl com/example/nested=" + resource); resource = cl.getResourceAsStream("top"); System.out.println("8: cl top=" + resource); resource = cl.getResourceAsStream("/top"); System.out.println("9: cl /top=" + resource); } }
The output from the program is:
程序的输出是:
1: A.class nested=java.io.BufferedInputStream@19821f 2: A.class /com/example/nested=java.io.BufferedInputStream@addbf1 3: A.class top=null 4: A.class /top=java.io.BufferedInputStream@42e816 5: cl nested=null 6: cl /com/example/nested=null 7: cl com/example/nested=java.io.BufferedInputStream@9304b1 8: cl top=java.io.BufferedInputStream@190d11 9: cl /top=null
Mostly things do what you'd expect. Case-3 fails because class relative resolving is with respect to the Class, so "top" means "/com/example/top", but "/top" means what it says.
大多数情况下,事情会按照您的预期进行。案例 3 失败,因为类相对解析是关于类的,所以“top”的意思是“/com/example/top”,而“/top”的意思是它所说的。
Case-5 fails because classloader relative resolving is with respect to the classloader. But, unexpectedly Case-6 also fails: one might expect "/com/example/nested" to resolve properly. To access a nested resource through the classloader you need to use Case-7, i.e. the nested path is relative to the root of the classloader. Likewise Case-9 fails, but Case-8 passes.
案例 5 失败,因为类加载器相对解析是关于类加载器的。但是,出乎意料的是,Case-6 也失败了:人们可能希望“/com/example/nested”能够正确解析。要通过类加载器访问嵌套资源,您需要使用 Case-7,即嵌套路径相对于类加载器的根目录。同样,案例 9 失败,但案例 8 通过。
Remember: for java.lang.Class, getResourceAsStream() does delegate to the classloader:
请记住:对于 java.lang.Class,getResourceAsStream() 确实委托给类加载器:
public InputStream getResourceAsStream(String name) { name = resolveName(name); ClassLoader cl = getClassLoader0(); if (cl==null) { // A system class. return ClassLoader.getSystemResourceAsStream(name); } return cl.getResourceAsStream(name); }
so it is the behavior of resolveName() that is important.
因此,resolveName() 的行为很重要。
Finally, since it is the behavior of the classloader that loaded the class that essentially controls getResourceAsStream(), and the classloader is often a custom loader, then the resource-loading rules may be even more complex. e.g. for Web-Applications, load from WEB-INF/classes or WEB-INF/lib in the context of the web application, but not from other web-applications which are isolated. Also, well-behaved classloaders delegate to parents, so that duplicateed resources in the classpath may not be accessible using this mechanism.
最后,由于加载类的行为本质上是控制 getResourceAsStream() 的类加载器,并且类加载器通常是自定义加载器,因此资源加载规则可能会更加复杂。例如,对于 Web 应用程序,从 Web 应用程序上下文中的 WEB-INF/classes 或 WEB-INF/lib 加载,而不是从其他隔离的 Web 应用程序加载。此外,行为良好的类加载器委托给父级,因此使用此机制可能无法访问类路径中的重复资源。
回答by Tristan Everitt
A JAR is basically a ZIP file so treat it as such. Below contains an example on how to extract one file from a WAR file (also treat it as a ZIP file) and outputs the string contents. For binary you'll need to modify the extraction process, but there are plenty of examples out there for that.
JAR 基本上是一个 ZIP 文件,因此请如此对待它。下面包含一个示例,说明如何从 WAR 文件(也将其视为 ZIP 文件)中提取一个文件并输出字符串内容。对于二进制,您需要修改提取过程,但是有很多示例可以做到这一点。
public static void main(String args[]) {
String relativeFilePath = "style/someCSSFile.css";
String zipFilePath = "/someDirectory/someWarFile.war";
String contents = readZipFile(zipFilePath,relativeFilePath);
System.out.println(contents);
}
public static String readZipFile(String zipFilePath, String relativeFilePath) {
try {
ZipFile zipFile = new ZipFile(zipFilePath);
Enumeration<? extends ZipEntry> e = zipFile.entries();
while (e.hasMoreElements()) {
ZipEntry entry = (ZipEntry) e.nextElement();
// if the entry is not directory and matches relative file then extract it
if (!entry.isDirectory() && entry.getName().equals(relativeFilePath)) {
BufferedInputStream bis = new BufferedInputStream(
zipFile.getInputStream(entry));
// Read the file
// With Apache Commons I/O
String fileContentsStr = IOUtils.toString(bis, "UTF-8");
// With Guava
//String fileContentsStr = new String(ByteStreams.toByteArray(bis),Charsets.UTF_8);
// close the input stream.
bis.close();
return fileContentsStr;
} else {
continue;
}
}
} catch (IOException e) {
logger.error("IOError :" + e);
e.printStackTrace();
}
return null;
}
In this example I'm using Apache Commons I/O and if you are using Maven here is the dependency:
在这个例子中,我使用的是 Apache Commons I/O,如果你使用的是 Maven,这里是依赖项:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
回答by hothead
Check first your class loader.
首先检查您的类加载器。
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = Class.class.getClassLoader();
}
classLoader.getResourceAsStream("xmlFileNameInJarFile.xml");
// xml file location at xxx.jar
// + folder
// + folder
// xmlFileNameInJarFile.xml
回答by he1ix
Just for completeness, there has recently been a questionon the Jython mailinglist where one of the answers referred to this thread.
为了完整起见,最近在 Jython 邮件列表上出现了一个问题,其中一个答案提到了这个线程。
The question was how to call a Python script that is contained in a .jar file from within Jython, the suggested answer is as follows (with "InputStream" as explained in one of the answers above:
问题是如何从 Jython 中调用包含在 .jar 文件中的 Python 脚本,建议的答案如下(使用“InputStream”,如上述答案之一所述:
PythonInterpreter.execfile(InputStream)