Java 读取jar包中的资源文件夹

个人博客原文地址:http://www.ltang.me/2016/07/19/Java-jar-read-resource/

最近在做一个工具包的时候,有这么一种需求:在运行main函数时,需要将resources资源文件夹下的xml子文件夹中的文件加载。原本可以使用Main.class.getClassLoader().getResoruceAsStream()将文件一一加载,但是xml子文件夹中的文件非常多,不可能一个个列文件名。所以最初我的写法是:

File parent = new File(ClassLoader.getSystemClassLoader().getResource("").getPath() + "/xml");
File[] files = parent.listFiles();
for (int i = 0; i < xmlFiles.length; i++) {
    File xmlFile = xmlFiles[i];
    //...
}

在IDE中运行并没有问题,能够正常得读取到资源文件夹和文件。但是当我使用maven将工程打成jar包,试图使用命令行启动时,跑到这里就会抛空指针异常了。不断的测试和查资料,终于明白,当打成一个jar包后,整个jar包是一个文件,只能使用流的方式读取资源,这时候就不能通过File来操作资源了,得通过getResourceAsStream来读取文件内容并操作。在IDE中之所以能正常运行,是因为IDE中的资源文件在target/classes目录下,是正常的文件系统结构。

然而问题来了,我不是读一个文件,而是试图读取一个文件夹,依次读取文件夹下所有文件资源。我试图按照网上的说法,读取资源,然后创建一个临时文件,在操作该临时文件,例:

File file = null;
URL res = PostHelper.class.getClassLoader().getResource("xml/");
if (res.toString().startsWith("jar:")) {
    try {
        InputStream input = PostHelper.class.getClassLoader().getResourceAsStream("xml/");
        file = File.createTempFile("tempfile", ".tmp");
        OutputStream out = new FileOutputStream(file);
        int read;
        byte[] bytes = new byte[1024];
        while ((read = input.read(bytes)) != -1) {
            out.write(bytes, 0, read);
        }
        file.deleteOnExit();
    } catch (IOException ex) {
        ex.printStackTrace();
    }
} else {
    file = new File(res.getFile());
}


然而这种方式,也只能操作文件,因为创建出来的是临时文件而非临时文件夹。估计还是有办法解决的,将输入流转为文件夹?这里我也没继续研究了,而是再次搜索解决方案。最终的解决方法如下所示,经过测试,可以完美解决这个问题,顺利读取资源子文件夹中所有文件:

URL url = Main.class.getClassLoader().getResource("xml/");
String jarPath = url.toString().substring(0, url.toString().indexOf("!/") + 2);

URL jarURL = new URL(jarPath);
JarURLConnection jarCon = (JarURLConnection) jarURL.openConnection();
JarFile jarFile = jarCon.getJarFile();
Enumeration<JarEntry> jarEntrys = jarFile.entries();

while (jarEntrys.hasMoreElements()) {
    JarEntry entry = jarEntrys.nextElement();
    String name = entry.getName();
    if (name.startsWith("xml/") && !entry.isDirectory()) {
        doWithInputStream(Main.class.getClassLoader().getResourceAsStream(name));
    }
}

猜你喜欢

转载自blog.csdn.net/devotedwife/article/details/81837205