我想读取一个在我的类路径中包含的jar
内的XML文件。如何读取任何包含在jar
中的文件?
如果您想从应用程序内部读取该文件,请使用以下方法:
InputStream input = getClass().getResourceAsStream("/classpath/to/my/file");
这个路径以“/”开头,但它并不是您文件系统中的路径,而是您类路径中的路径。所以如果您的文件在类路径“org.xml”下,并且名为myxml.xml,则您的路径看起来像“/org/xml/myxml.xml”。
InputStream读取文件内容。如果需要,您可以将其包装成Reader。
啊,这是我最喜欢的主题之一。你可以通过类路径加载资源的基本上有两种方法:
Class.getResourceAsStream(resource)
和
ClassLoader.getResourceAsStream(resource)
(还有其他方法可以类似地获取资源的URL,然后打开连接,但这是两种直接的方法)。
第一种方法实际上是委托给第二种方法,在混淆资源名称后。基本上有两种资源名称:绝对路径(例如“/ path / to / resource / resource”)和相对路径(例如“resource”)。绝对路径以“/”开头。
以下示例应该能说明问题。考虑一个名为com.example.A的类。在类路径中,考虑位于/com/example/nested和/top的两个资源。以下程序显示了访问这两个资源的9种可能方式:
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); }
}
该程序的输出为:
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
大多数情况下都是按预期进行的。 第3个案例失败,因为相对于Class的类相关解析是以“/com/example/top”为基础,但“/top”表示其本身。
案例5失败,因为类加载器相对解析是相对于类加载器的。 但是,出人意料的是,案例6也失败了:可以预期“/com/example/nested”会正确解析。 要通过类加载器访问嵌套资源,您需要使用Case-7,即嵌套路径相对于类加载器的根目录。 同样,案例9失败,但案例8成功。
请记住:对于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); }
因此,在重要的resolveName()行为。
最后,由于实际控制getResourceAsStream的是加载类的类加载器的行为,并且类加载器通常是自定义加载程序,因此资源加载规则可能会更加复杂。例如Web应用程序,从Web应用程序的上下文中的WEB-INF/classes或WEB-INF/lib加载,但不从其他被隔离的Web应用程序加载。此外,行为良好的类加载器会委托给父代,因此在类路径中重复的资源
首先检查你的类加载器。
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
JAR基本上就是一个ZIP文件,因此可以将其视为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;
}
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
这也适用于Spring
ClassPathResource resource = new ClassPathResource("/file.txt", MainApplication.class); //resources folder
InputStream inputStream = resource.getInputStream();
File file = new File("file.txt");
FileUtils.copyInputStreamToFile(inputStream, file);
仅为完整起见,最近在Jython邮件列表上出现了一个问题,其中一个答案引用了这个线程。
问题是如何从Jython中调用包含在.jar文件中的Python脚本,建议的答案如下(使用上面某个答案中解释的"InputStream"):
PythonInterpreter.execfile(InputStream)
try(InputStream inputStream = this.getClass()
.getClassLoader()
.getResourceAsStream("common/test.yaml")) {
//Your code
} catch (Exception e) {
LOGGER.error(e);
}