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

评论

参见stackoverflow.com/questions/16842306

如果要从jar中的目录中读取文件,其中包含文件的任何编号,请参见Stackoverflow-Link

#1 楼

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

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


路径以“ /”开头,但不是文件系统中的路径,但是在你的classpath中。因此,如果您的文件位于类路径“ org.xml”中,并且名为myxml.xml,则您的路径类似于“ /org/xml/myxml.xml”。

InputStream读取文件的内容。如果需要,可以将其包装到阅读器中。

希望对您有所帮助。

#2 楼

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



 Class.getResourceAsStream(resource)
 




 ClassLoader.getResourceAsStream(resource)
 


(还有其他方法可以获取资源的URL以类似的方式,然后打开到它的连接,但这是两种直接方式。

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

这是一个例子,应该说明。考虑类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);
    }

}


该程序的输出为:

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


大多数事情都能达到您的期望。 Case-3失败是因为类相对于类是相对于类的,所以“ top”表示“ / com / example / top”,而“ / top”表示其含义。

Case-5失败,因为类加载器的相对解析是针对类加载器的。但是,出乎意料的是Case-6也会失败:人们可能希望“ / com / example / nested”能够正确解决。要通过类加载器访问嵌套资源,您需要使用Case-7,即,嵌套路径相对于类加载器的根目录。同样,Case-9失败,但Case-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 / class或WEB-INF / lib加载,但不能从隔离的其他Web应用程序中加载。此外,行为良好的类加载器还会委派给父级,这样,使用此机制可能无法访问类路径中的重复资源。

评论


这基本上与我给出的答案相同,但更详细地解释了。 +1

–Mnementh
10年8月2日在10:52

这是提到的resolveName方法:gist.github.com/briangordon/5374626

–布赖恩·戈登(Brian Gordon)
13年4月12日在19:51

#3 楼

首先检查您的类加载器。

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


#4 楼

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>


#5 楼

为了完整起见,Jython邮件列表上最近出现了一个问题,其中的答案之一就是与此线程相关。

问题是如何从.js文件中调用.jar文件中包含的Python脚本。在Jython中,建议的答案如下(使用“ InputStream”,如以上答案之一所述:

PythonInterpreter.execfile(InputStream)