﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-leon-yi</title><link>http://www.blogjava.net/leon-yi/</link><description /><language>zh-cn</language><lastBuildDate>Thu, 07 May 2026 03:20:10 GMT</lastBuildDate><pubDate>Thu, 07 May 2026 03:20:10 GMT</pubDate><ttl>60</ttl><item><title>在Jar中读取Jar包中的资源（文本、图片等文件）</title><link>http://www.blogjava.net/leon-yi/archive/2010/12/10/jar_resource.html</link><dc:creator>leon.yi</dc:creator><author>leon.yi</author><pubDate>Fri, 10 Dec 2010 06:21:00 GMT</pubDate><guid>http://www.blogjava.net/leon-yi/archive/2010/12/10/jar_resource.html</guid><wfw:comment>http://www.blogjava.net/leon-yi/comments/340253.html</wfw:comment><comments>http://www.blogjava.net/leon-yi/archive/2010/12/10/jar_resource.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/leon-yi/comments/commentRss/340253.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/leon-yi/services/trackbacks/340253.html</trackback:ping><description><![CDATA[<p>我们常常在代码中读取一些资源文件(比如图片，音乐，文本等等)。在单独运行的时候这些简单的处理当然不会有问题。但是，如果我们把代码打成一个jar包以后，即使将资源文件一并打包，这些东西也找不出来了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这段代码写在Eclipse建立的java Project中，其目录为：(其中将资源文件res.txt放在了bin目录下，以便打成jar包)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、src/<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; src/edu/hxraid/Resource.java<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2、bin/<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bin/resource/res.txt<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bin/edu/hxraid/Resource.class</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 很显然运行源代码1是能够找到资源文件res.txt。但当我们把整个工程打成jar包以后(ResourceJar.jar)，这个jar包内的目录为：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; edu/hxraid/Resource.class<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; resource/res.txt</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 而这时jar包中Resource.class字节码：ldc &lt;String "bin/resource/res.txt"&gt; [20] 将无法定位到jar包中的res.txt位置上。就算把bin/目录去掉：ldc &lt;String "resource/res.txt"&gt; [20] 仍然无法定位到jar包中res.txt上。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这主要是因为jar包是一个单独的文件而非文件夹，绝对不可能通过"file:/e:/.../ResourceJar.jar/resource /res.txt"这种形式的文件URL来定位res.txt。所以即使是相对路径，也无法定位到jar文件内的txt文件(读者也许对这段原因解释有些费解，在下面我们会用一段代码运行的结果来进一步阐述)。</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 那么把资源打入jar包，无论ResourceJar.jar在系统的什么路径下，jar包中的字节码程序都可以找到该包中的资源。这会是幻想吗？</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当然不是，我们可以用类装载器(ClassLoader)来做到这一点：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (1) ClassLoader 是类加载器的抽象类。它可以在运行时动态的获取加载类的运行信息。 可以这样说，当我们调用ResourceJar.jar中的Resource类时，JVM加载进Resource类，并记录下Resource运行时信息(包括Resource所在jar包的路径信息)。而ClassLoader类中的方法可以帮助我们动态的获取这些信息:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ● public URL getResource(String name) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 查找具有给定名称的资源。资源是可以通过类代码以与代码基无关的方式访问的一些数据(图像、声音、文本等)。并返回资源的URL对象。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ● public InputStream getResourceAsStream(String name); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 返回读取指定资源的输入流。这个方法很重要，可以直接获得jar包中文件的内容。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (2) ClassLoader是abstract的，不可能实例化对象，更加不可能通过ClassLoader调用上面两个方法。所以我们真正写代码的时候，是通过Class类中的getResource()和getResourceAsStream()方法，这两个方法会委托ClassLoader中的getResource()和getResourceAsStream()方法 。好了，现在我们重新写一段Resource代码,来看看上面那段费解的话是什么意思了：<br />
Java代码 <br />
//源代码2：&nbsp; <br />
package edu.hxraid;&nbsp; <br />
import java.io.*;&nbsp; <br />
import java.net.URL;&nbsp; <br />
public class Resource {&nbsp; <br />
&nbsp;&nbsp;&nbsp; public&nbsp; void getResource() throws IOException{&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //查找指定资源的URL，其中res.txt仍然开始的bin目录下&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; URL fileURL=this.getClass().getResource("/resource/res.txt");&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(fileURL.getFile());&nbsp; <br />
&nbsp;&nbsp;&nbsp; }&nbsp; <br />
&nbsp;&nbsp;&nbsp; public static void main(String[] args) throws IOException {&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Resource res=new Resource();&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; res.getResource();&nbsp; <br />
&nbsp;&nbsp;&nbsp; }&nbsp; <br />
}&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 运行这段源代码结果：/E:/Code_Factory/WANWAN/bin/resource/res.txt&nbsp; (../ Code_Factory/WANWAN/.. 是java project所在的路径)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们将这段代码打包成ResourceJar.jar ,并将ResourceJar.jar放在其他路径下(比如 c:\ResourceJar.jar)。然后另外创建一个java project并导入ResourceJar.jar，写一段调用jar包中Resource类的测试代码：<br />
Java代码 <br />
import java.io.IOException;&nbsp; <br />
import edu.hxraid.Resource;&nbsp; <br />
public class TEST {&nbsp; <br />
&nbsp;&nbsp;&nbsp; public static void main(String[] args) throws IOException {&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Resource res=new Resource();&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; res.getResource();&nbsp; <br />
&nbsp;&nbsp;&nbsp; }&nbsp; <br />
}&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这时的运行结果是：file:/C:/ResourceJar.jar!/resource/res.txt</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们成功的在运行时动态获得了res.txt的位置。然而，问题来了，你是否可以通过下面这样的代码来得到res.txt文件？<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File f=new File("C:/ResourceJar.jar!/resource/res.txt");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当然不可能，因为".../ResourceJar.jar!/resource/...."并不是文件资源定位符的格式 (jar中资源有其专门的URL形式：jar:&lt;url&gt;!/{entry} )。所以，如果jar包中的类源代码用File f=new File(相对路径);的形式，是不可能定位到文件资源的。这也是为什么源代码1打包成jar文件后，调用jar包时会报出FileNotFoundException的症结所在了。</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (3) 我们不能用常规操作文件的方法来读取ResourceJar.jar中的资源文件res.txt，但可以通过Class类的getResourceAsStream()方法来获取 ，这种方法是如何读取jar中的资源文件的，这一点对于我们来说是透明的。我们将Resource.java改写成：<br />
Java代码 <br />
//源代码3：&nbsp; <br />
package edu.hxraid;&nbsp; <br />
import java.io.*;&nbsp; <br />
public class Resource {&nbsp; <br />
&nbsp;&nbsp;&nbsp; public void getResource() throws IOException{&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //返回读取指定资源的输入流&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InputStream is=this.getClass().getResourceAsStream("/resource/res.txt");&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedReader br=new BufferedReader(new InputStreamReader(is));&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String s="";&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while((s=br.readLine())!=null)&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(s);&nbsp; <br />
&nbsp;&nbsp;&nbsp; }&nbsp; <br />
}&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们将java工程下/bin目录中的edu/hxraid/Resource.class和资源文件resource/res.txt一并打包进ResourceJar.jar中，不管jar包在系统的任何目录下，调用jar包中的Resource类都可以获得jar包中的res.txt资源，再也不会找不到res.txt文件了。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>注：有现在的jar包可以直接用于解决这个问题。</p>
<p>当然这种工作，前人也早已经研究过了。XWork中有个工具类，叫做ClassLoaderUtil，可以深入读取jar包中的资源文件。Struts2就是用这个工具类读取所有的plugin中的struts-default.xml的。例如用户可以下载xwork-core-2.1.4-jdk14.jar,里面包括有一个类ClassLoaderUtil.java,其中的静态函数</p>
<p>getResourceAsStream(String resourceName, Class callingClass)也可以解决这个问题。</p>
<p>ClassLoaderUtil.getResourceAsStream(<br />
&nbsp;&nbsp;&nbsp; "wei.txt", String.class);<br />
<br />
TrackURL: http://www.javaeye.com/topic/483115</p>
 <img src ="http://www.blogjava.net/leon-yi/aggbug/340253.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/leon-yi/" target="_blank">leon.yi</a> 2010-12-10 14:21 <a href="http://www.blogjava.net/leon-yi/archive/2010/12/10/jar_resource.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>