- 浏览: 897485 次
- 性别:
- 来自: 武汉
文章分类
最新评论
-
小宇宙_WZY:
膜拜一下大神,解决了我一个大问题,非常感谢 orz
【解惑】深入jar包:从jar包中读取资源文件 -
JKL852qaz:
感谢,遇到相同的问题!
【解惑】深入jar包:从jar包中读取资源文件 -
lgh1992314:
为什么java中调用final方法是用invokevirtua ...
【解惑】Java动态绑定机制的内幕 -
鲁曼1991:
说的都有道理,protected只能被同一级包的类所调用
【解惑】真正理解了protected的作用范围 -
鲁曼1991:
...
【总结】String in Java
我们常常在代码中读取一些资源文件(比如图片,音乐,文本等等)。在单独运行的时候这些简单的处理当然不会有问题。但是,如果我们把代码打成一个jar包以后,即使将资源文件一并打包,这些东西也找不出来了。看看下面的代码:
//源代码1: package edu.hxraid; import java.io.*; public class Resource { public void getResource() throws IOException{ File file=new File("bin/resource/res.txt"); BufferedReader br=new BufferedReader(new FileReader(file)); String s=""; while((s=br.readLine())!=null) System.out.println(s); } }
这段代码写在Eclipse建立的java Project中,其目录为:(其中将资源文件res.txt放在了bin目录下,以便打成jar包)
1、src/
src/edu/hxraid/Resource.java
2、bin/
bin/resource/res.txt
bin/edu/hxraid/Resource.class
很显然运行源代码1是能够找到资源文件res.txt。但当我们把整个工程打成jar包以后(ResourceJar.jar),这个jar包内的目录为:
edu/hxraid/Resource.class
resource/res.txt
而这时jar包中Resource.class字节码:ldc <String "bin/resource/res.txt"> [20] 将无法定位到jar包中的res.txt位置上。就算把bin/目录去掉:ldc <String "resource/res.txt"> [20] 仍然无法定位到jar包中res.txt上。
这主要是因为jar包是一个单独的文件而非文件夹,绝对不可能通过"file:/e:/.../ResourceJar.jar/resource /res.txt"这种形式的文件URL来定位res.txt。所以即使是相对路径,也无法定位到jar文件内的txt文件(读者也许对这段原因解释有些费解,在下面我们会用一段代码运行的结果来进一步阐述)。
那么把资源打入jar包,无论ResourceJar.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()方法 。好了,现在我们重新写一段Resource代码,来看看上面那段费解的话是什么意思了:
//源代码2: 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
我们成功的在运行时动态获得了res.txt的位置。然而,问题来了,你是否可以通过下面这样的代码来得到res.txt文件?
File f=new File("C:/ResourceJar.jar!/resource/res.txt");
当然不可能,因为".../ResourceJar.jar!/resource/...."并不是文件资源定位符的格式
(jar中资源有其专门的URL形式:
jar:<url>!/{entry}
)。所以,如果jar包中的类源代码用File f=new File(相对路径);的形式,是不可能定位到文件资源的。这也是为什么源代码1打包成jar文件后,调用jar包时会报出FileNotFoundException的症结所在了。
(3) 我们不能用常规操作文件的方法来读取ResourceJar.jar中的资源文件res.txt,但可以通过Class类的getResourceAsStream()方法来获取 ,这种方法是如何读取jar中的资源文件的,这一点对于我们来说是透明的。我们将Resource.java改写成:
//源代码3: 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); } }
我们将java工程下/bin目录中的edu/hxraid/Resource.class和资源文件resource/res.txt一并打包进ResourceJar.jar中,不管jar包在系统的任何目录下,调用jar包中的Resource类都可以获得jar包中的res.txt资源,再也不会找不到res.txt文件了。
评论
原来我的资源文件名是 BigramDict.dct
但是我在源代码里面写成了:/ICTCLAS_DICT/bigramDict.dct (首字母小写了)
本来这是个小问题,但是源代码
InputStream is=this.getClass().getResourceAsStream("/ICTCLAS_DICT/bigramDict.dct");
运行的时候是可以找到BigramDict.dct的。一旦把 BigramDict.dct打入jar包,就找不到了。
jar包里面的文件要分大小写的,但找外面的文件名可以不分,哭死我了。
我想骂..骂..骂..骂..骂...娘....
这个问题我也遇到过。。。浪费了我N多时间,才发现时文件名大小写问题。。。差点崩溃
原来我的资源文件名是 BigramDict.dct
但是我在源代码里面写成了:/ICTCLAS_DICT/bigramDict.dct (首字母小写了)
本来这是个小问题,但是源代码
InputStream is=this.getClass().getResourceAsStream("/ICTCLAS_DICT/bigramDict.dct");
运行的时候是可以找到BigramDict.dct的。一旦把 BigramDict.dct打入jar包,就找不到了。
jar包里面的文件要分大小写的,但找外面的文件名可以不分,哭死我了。
我想骂..骂..骂..骂..骂...娘....
getClass().getResource("a.txt").getPath().replaceAll("%20", " ")
第一种从根目录(当前类的最外层包的父目录)搜索资源;
第二种从当前类所在目录搜索资源。
就可以搞定了。。。
类加载器加载的资源文件都要在classpath下
File f = new File(URL.getFile());
这样就可以了。但是带来的问题是URL的路径中不支持文件夹包含空格(用%20代替了),如果要使用,需要再次转义。
虽然新的URI支持空格。但是URL.toURI().getPath()却不能够作为参数new出一个File对象。
确实是这样,当时这个格式不同于file的URL格式,所以我们不能通过File f=new File(jarURL);来获取jar中的资源,只能通过专门的方法来定位jar包中专门的URL格式。这个方法就是ClassLoader的getResourceAsStream()方法,至于是如何做到的,我就不知道了,这个方法是透明的。
例如:jar:file:/.../.../xxx.jar!/.../.../zzz.class
原理应该和楼主的一样。所以不得不赞叹很多前人的工作,当我们碰到难题时,其实很多前人已经总结了很多最佳实践了。
发表评论
-
NIO
2010-08-05 10:36 0在JDK1.4以前,I/O输入输出处理,我们把它称为旧 ... -
【总结】Java线程同步机制深刻阐述
2010-05-16 10:21 6002全文转载:http://www.iteye ... -
【JDK优化】java.util.Arrays的排序研究
2010-05-12 21:06 9186作者题记:JDK中有很多算法具有优化的闪光点,值得好好研究。 ... -
【JDK优化】 Integer 自动打包机制的优化
2010-03-12 19:14 4189我们首先来看一段代码: Integer i=100; In ... -
【总结】Java与字符编码问题详谈
2009-12-30 09:11 9424一、字符集和字符编码方式 计算机只懂得0/1两种信号 ... -
【解惑】 正确理解线程等待和释放(wait/notify)
2009-12-29 13:40 19756对于初学者来说,下面这个例子是一个非常常见的错误。 /** ... -
【解惑】JVM如何理解Java泛型类
2009-12-16 11:08 12372//泛型代码 public class Pair<T& ... -
【解惑】正确的理解this 和 super
2009-12-05 09:46 4469转载: 《无聊 ... -
【解惑】真正理解了protected的作用范围
2009-11-21 18:00 5086一提到访问控 ... -
【总结】String in Java
2009-11-21 17:52 10976作者:每次上网冲杯Java时,都能看到关于String无休无止 ... -
【解惑】真正理解了protected的作用范围
2009-11-16 17:11 585一提到访问控制符protected,即使是初学者 ... -
总结Java标准类库中类型相互转化的方法
2009-11-09 21:57 210组一: ☆ String → byte[ ... -
方法没覆盖住带来的烦恼
2009-11-05 09:18 100Object类是所有类的祖宗,它的equals方法比较的 ... -
【解惑】数组向上转型的陷阱
2009-11-03 11:44 1887问题提出: 有两个类Manager和Em ... -
【总结】java命令解析以及编译器,虚拟机如何定位类
2009-11-01 16:25 5813学Java有些日子了,一直都使用IDE来写程序。这 ... -
【解惑】剖析float型的内存存储和精度丢失问题
2009-10-26 15:10 16062问题提出:12.0f-11.9f=0.10 ... -
【解惑】领略内部类的“内部”
2009-10-19 15:38 3596内部类有两种情况: (1) 在类中定义一个类(私有内部类 ... -
【解惑】理解java枚举类型
2009-09-26 09:37 3422枚举类型是JDK5.0的新特征。Sun引进了一个全新的关键字e ... -
编写自己的equals方法
2009-09-20 14:18 129在我的《令人头疼的"相等"关 ... -
【解惑】Java类型间的转型
2009-09-11 16:03 5679★ 基本数据类型间的转换 1、Java要做到平台无关 ...
相关推荐
城投解惑系列之五:计划外“再融资债”,有何变化?-20201229-广发证券-14页.pdf
机械行业“解惑”系列十:装配式建筑对中大型塔吊的需求缺口测算_广发证券-35页.pdf
更进一步,MANIFEST.MF 文件是 JAR 文件的核心元数据文件,它提供了关于 JAR 包的详细信息,包括主类(Main-Class)等。标准的 MANIFEST.MF 文件通常包含更多属性,如版本信息、实现厂商等。例如: ``` Manifest-...
CustomLib为jar包原项目,UnityAddAndroid为Unity项目,UnityAndroidPackage为UnityAddAndroid打包成的安卓项目,为了页面交互加入了mylibrary作为安卓原生….zip项目工程资源经过严格测试可直接运行成功且功能正常...
提供jar包 以供使用.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会...
Rsession提供了一种简单的方式,让Java可以访问远程或本地的Rserve实例。Rsession是对Rserve的封装,提供了更高层的API...关于R和Java通信的其他文章,请参考:解惑rJava R与Java的高速通道, Rserve与Java的跨平台通信
项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松copy复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全栈开发),有任何使用问题欢迎随时与我联系,我会及时为您解惑,...
1.文件传输速度太慢,可以创建发送和接收缓存提高传输速度,最简单的办法就是加大UDP包大小,设置MyPacket.java 文件里变量packetLength = 1024*50;后速度会有很大提高.. 2.在文件传输过程中,再发消息会丢包(接收方收...
《C语言解惑》这本书是为了解决C语言学习者在编程过程中遇到的困惑而编写的,它通过一系列精心设计的编程谜题帮助读者深入理解C语言的核心概念和机制。这个压缩包文件包含了书中所有谜题的源代码,是学习和实践C语言...
5. **精通Java——JDK.rar**:这个压缩文件可能包含了一套关于JDK的深入学习资料,涵盖了JDK的各个组件,如JVM、类库、API等,有助于开发者从基础到高级全面提升Java技能。 6. **Java 十大基础笔记整理(PDF).zip*...
### Java解惑知识点详解 #### 一、表达式谜题 **谜题1:奇数性** - **描述**:程序看似应该返回一个布尔值,表明一个数字是否为奇数,但结果却出乎意料。 - **解惑**:在进行模运算时,需要注意负数的情况。当输入...
项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松copy复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全栈开发),有任何使用问题欢迎随时与我联系,我会及时为您解惑,...
机械行业“解惑”系列之九:进击的小挖和“消失”的农民工,挖掘机的劳动力替代效应 从本报告中,我们可以总结出以下几个知识点: 1.机械行业“解惑”系列之九:报告介绍了小型挖掘机在机械行业中的崛起和农民工...
### C语言解惑知识点概述 ...无论是对于初学者还是有一定基础的开发者来说,《C语言解惑》都是一本值得拥有的宝贵资源。希望读者能够通过阅读本书,不断提升自己的编程技能,解决实际开发中遇到的问题。
"java解惑"这个主题旨在帮助初学者理解和解决在学习Java过程中遇到的问题,通过实例来深入浅出地讲解Java的基础知识,同时也强调了实用技巧和注意事项。 "Java解惑"的资料可能包含了两部分:`.chm`和`.pdf`格式的...
《IT解惑》是一部综合性的资源集合,包含了《IT...这三部作品结合在一起,为IT学习者和从业人员提供了一条全面的学习和发展路径,从基础学习到职业规划,再到具体的编程实践,都有详尽的指导,是一份宝贵的IT解惑资源。
下面,我们将深入探讨一些常见的Java解惑知识点。 1. **Java基础** - **变量与数据类型**:Java支持基本数据类型(如int、double等)和引用类型(如类、接口和数组)。理解它们的区别对于正确使用变量至关重要。 ...
《Java解惑(中文版)》是一本专为Java初学者设计的学习资料,旨在帮助读者解答在学习Java过程中遇到的各种困惑。"solve65p"可能代表这本书包含65个问题或主题,每个都深入浅出地进行了讲解,旨在解决初学者在编程...
通过注册表文件解决简单的PS不能读取系统剪贴板的问题 网页摘取 “编写一个如下内容的reg文件,然后导入注册表就可以搞定。 Windows Registry Editor Version 5.00 [HKEY_CURRENT_...
城投解惑系列之十九:2021年隐性债务置换试点知多少?.rar