如何读取jar包中的资源文件?
读取jar包中的资源文件使用常规的方法是不行的,需要使用类加载器ClassLoader及其相关方法。
1.ClassLoader 是类加载器的抽象类。
她可以在运行时动态的获取加载类的运行信息。 可以这样说,当我们调用ResourceJar.jar中的Resource类时,JVM加载进Resource类,并记录下Resource运行时信息(包括Resource所在jar包的路径信息)。而ClassLoader类中的方法可以帮助我们动态的获取这些信息。
- public URL getResource(String name)
查找具有给定名称的资源。资源可以通过类代码访问并返回资源的URL对象。 - public InputStream getResourceAsStream(String name);
返回读取指定资源的输入流。这个方法很重要,可以直接获得jar包中文件的内容。
2.ClassLoader是abstract的,不可能实例化,更不可能通过ClassLoader调用上面两个方法。
所以我们真正写代码的时候,是通过Class类中的getResource()和getResourceAsStream()方法,这两个方法会委托ClassLoader中的getResource()和getResourceAsStream()方法 。
package edu.hxraid;
import java.io.*;
import java.net.URL;
public class Resource {
public void getResource() throws IOException{
//查找指定资源的URL,其中res.txt仍然开始的bin目录下
URL fileURL=this.getClass().getResource("/resource/res.txt");
System.out.println(fileURL.getFile());
}
public static void main(String[] args) throws IOException {
Resource res=new Resource();
res.getResource();
}
}
运行这段源代码结果:/E:/Code_Factory/WANWAN/bin/resource/res.txt (../ Code_Factory/WANWAN/.. 是java project所在的路径)。
我们将这段代码打包成ResourceJar.jar ,并将ResourceJar.jar放在其他路径下(比如 c:\ResourceJar.jar)。然后另外创建一个java project并导入ResourceJar.jar,写一段调用jar包中Resource类的测试代码:
import java.io.IOException;
import edu.hxraid.Resource;
public class TEST {
public static void main(String[] args) throws IOException {
Resource res=new Resource();
res.getResource();
}
}
这时的运行结果是:file:/C:/ResourceJar.jar!/resource/res.txt
当然不可以使用如下形式引用资源
File f=new File("C:/ResourceJar.jar!/resource/res.txt");
jar中的资源有其专门的格式
这也就是为什么源代码打包成jar文件后,调用时会报出FileNotFoundException的原因所在了。
3.使用Class类的getResourceAsStream()方法来获取jar包中的资源。
package edu.hxraid;
import java.io.*;
public class Resource {
public void getResource() throws IOException{
//返回读取指定资源的输入流
InputStream is=this.getClass().getResourceAsStream("/resource/res.txt");
BufferedReader br=new BufferedReader(new InputStreamReader(is));
String s="";
while((s=br.readLine())!=null)
System.out.println(s);
}
}
4.其他
读取jar文件中的文件,用类加载器,亦可以读取到文件。URL中有一个getFile()方法。
File f = new File(URL.getFile());
但这种方法URL的路径中不支持中文和空格(用%20代替了)。可以:
getClass().getResource("/a.txt").getPath().replaceAll("%20", " ")
getClass().getResource("a.txt").getPath().replaceAll("%20", " ")
第一种从根目录(当前类的最外层包的父目录)搜索资源;
第二种从当前类所在目录搜索资源。
类加载器加载的资源文件都要在classpath下。
还需注意的是路径在windows文件系统中时是不分大小写的,但一旦打入jar包就大小写敏感了。