简体   繁体   English

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

[英]How to read a file from jar in Java?

I want to read an XML file that is located inside one of the jar s included in my class path.我想读取位于我的类路径中包含的jar之一内的 XML 文件。 How can I read any file which is included in the jar ?如何读取jar包含的任何文件?

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. InputStream 读取文件的内容。 You can wrap it into an Reader, if you want.如果需要,您可以将其包装到 Reader 中。

I hope that helps.我希望这有帮助。

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 (eg "/path/to/resource/resource") and relative (eg "resource").基本上有两种资源名称:绝对(例如“/path/to/resource/resource”)和相对(例如“资源”)。 Absolute paths start with "/".绝对路径以“/”开头。

Here's an example which should illustrate.这是一个应该说明的例子。 Consider a class com.example.A.考虑一个类 com.example.A。 Consider two resources, one located at /com/example/nested, the other at /top, in the classpath.考虑两个资源,一个位于类路径中的 /com/example/nested,另一个位于 /top。 The following program shows nine possible ways to access the two resources:以下程序显示了访问这两种资源的九种可能方式:

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.案例 5 失败,因为类加载器相对解析是关于类加载器的。 But, unexpectedly Case-6 also fails: one might expect "/com/example/nested" to resolve properly.但是,出乎意料的是,Case-6 也失败了:人们可能希望“/com/example/nested”能够正确解析。 To access a nested resource through the classloader you need to use Case-7, ie the nested path is relative to the root of the classloader.要通过类加载器访问嵌套资源,您需要使用 Case-7,即嵌套路径相对于类加载器的根目录。 Likewise Case-9 fails, but Case-8 passes.同样,案例 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.最后,由于加载类的行为本质上是控制 getResourceAsStream() 的类加载器,并且类加载器通常是自定义加载器,因此资源加载规则可能会更加复杂。 eg 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.例如,对于 Web 应用程序,从 Web 应用程序上下文中的 WEB-INF/classes 或 WEB-INF/lib 加载,而不是从其他隔离的 Web 应用程序加载。 Also, well-behaved classloaders delegate to parents, so that duplicateed resources in the classpath may not be accessible using this mechanism.此外,行为良好的类加载器委托给父级,因此使用此机制可能无法访问类路径中的重复资源。

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

A JAR is basically a ZIP file so treat it as such. JAR 基本上是一个 ZIP 文件,因此请如此对待它。 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.下面包含一个示例,说明如何从 WAR 文件(也将其视为 ZIP 文件)中提取一个文件并输出字符串内容。 For binary you'll need to modify the extraction process, but there are plenty of examples out there for that.对于二进制,您需要修改提取过程,但是有很多示例可以做到这一点。

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>

Just for completeness, there has recently been a question on 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)

This also works on 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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM