如何在Java中从jar读取文件?

我想读取位于我的类路径中包含的jar之一的XML文件。 我怎样才能读取包含在jar中的任何文件?

如果你想从你的应用程序中读取这个文件,使用:

 InputStream input = getClass().getResourceAsStream("/classpath/to/my/file"); 

路径以“/”开头,但不是文件系统中的路径,而是类路径中的路径。 因此,如果您的文件位于classpath“org.xml”并且名为myxml.xml,那么您的路径看起来像“/org/xml/myxml.xml”。

InputStream读取文件的内容。 如果你愿意的话,你可以把它换成一个阅读器。

我希望有帮助。

啊,这是我最喜欢的科目之一。 基本上有两种方法可以通过类路径加载资源:

 Class.getResourceAsStream(resource) 

 ClassLoader.getResourceAsStream(resource) 

(还有其他一些方法,包括以类似的方式获取资源的URL,然后打开一个连接,但这是两个直接的方式)。

第一个方法实际上委托给第二个,在修改资源名称之后。 基本上有两种资源名称:绝对的(例如“/ path / to / resource / resource”)和相对的(例如“resource”)。 绝对路径以“/”开头。

这是一个应该说明的例子。 考虑一个类com.example.A。 考虑两个资源,一个位于/ com / example / nested,另一个位于/ top,位于classpath中。 以下程序显示了九种可能的方式来访问这两个资源:

包com.example;

公开课A {

    公共静态无效的主要(字符串参数[]){

         // 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嵌套= 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

大部分事情都是你所期望的。 第三种情况是因为类相对于类的解析失败,所以“top”的意思是“/ 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){
             //系统类
            返回ClassLoader.getSystemResourceAsStream(name);
         }
        返回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文件,所以如此对待它。 下面包含一个关于如何从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; } 

在这个例子中,我使用Apache Commons I / O,如果你使用的是Maven,那么这个依赖关系是:

 <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> 

为了完整起见,最近有一个关于Jython邮件列表的问题 ,其中一个答案提到了这个线程。

问题是如何从Jython中调用包含在.jar文件中的Python脚本,建议的答案如下(在上面的答案中解释为“InputStream”:

 PythonInterpreter.execfile(InputStream)