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

如何在Java中从jar读取文件?,java,file-io,jar,Java,File Io,Jar,我想读取一个XML文件,该文件位于类路径中包含的一个JAR中。如何读取jar中包含的任何文件?如果要从应用程序内部读取该文件,请使用: InputStream input = getClass().getResourceAsStream("/classpath/to/my/file"); 路径以/开头,但这不是文件系统中的路径,而是类路径中的路径。因此,如果您的文件位于classpath org.xml,并且名为myxml.xml,那么您的路径看起来像/org/xml/myxml.xml In

我想读取一个XML文件,该文件位于类路径中包含的一个JAR中。如何读取jar中包含的任何文件?

如果要从应用程序内部读取该文件,请使用:

InputStream input = getClass().getResourceAsStream("/classpath/to/my/file");
路径以/开头,但这不是文件系统中的路径,而是类路径中的路径。因此,如果您的文件位于classpath org.xml,并且名为myxml.xml,那么您的路径看起来像/org/xml/myxml.xml

InputStream读取文件的内容。如果你愿意,你可以把它包装成阅读器


我希望这有帮助。

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

Class.getResourceAsStreamresource 及

ClassLoader.getResourceAsStreamresource 还有其他方法,包括以类似的方式获取资源的URL,然后打开与它的连接,但这是两种直接的方法

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

这里有一个例子可以说明。考虑一个类COM。考虑两个资源,一个位于/COM/示例/嵌套,另一个位于/Stof,在类路径中。以下程序显示了访问这两个资源的九种可能方式:

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失败,因为类相对解析是关于类的,所以top表示/com/example/top,但/top表示它所说的内容

案例5失败,因为类加载器相对解析是关于类加载器的。但是,出乎意料的是,Case-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,并且类装入器通常是一个自定义装入器,因此资源装入规则可能更加复杂。e、 g.对于Web应用程序,从Web应用程序上下文中的Web-INF/classes或Web-INF/lib加载,但不要从其他孤立的Web应用程序加载。此外,行为良好的类加载器将委托给父类,因此使用此机制可能无法访问类路径中的重复资源。

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;
}
在本例中,我使用的是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)

这与我给出的答案基本相同,但解释得更详细+1这里有一个提到的resolveName方法:查看是否要从jar中的目录中读取文件,以及文件的编号,请参阅
PythonInterpreter.execfile(InputStream)