可能有不少初学者会有这样的困惑(以前我也有过):在你的代码里调用了一些资源文件,如图片,音乐等,在调试环境或单独运行的时候可以正常显示或播放,而一旦打包到jar文件中,这些东东就再也出不来了,除非把这个jar放到原来未打包以前的目录下,但通常jar是单独发布的。这里介绍一个解决这类问题的方法。
getResource和getResourceAsStream
问题的根源还是在于老生常谈的所谓class path,不信的话你在系统环境变量里的ClassPath加上你的jar文件,这下你就看得到你的图片了!但单独发布jar的话不可能指望每次都让用户为你的jar而专门修改classpath。那么有没有什么办法一劳永逸地搞定它呢?我们需要从类的装载入手。先扯远一点,在开发JSP之类的Web应用程序的时候要用到第三方的库怎么办?通常的做法是把这些库(可以是class,也可以是jar)统统放到WEB-INF/lib/目录下面,为什么这样系统就认了呢?因为Web容器(譬如Tomcat)在装载类的时候有自己的组织方式(可以参考Tomcat手册http://jakarta.apache.org/tomcat/tomcat-4.1-doc/class-loader-howto.html)。特别地,jar也是类装载器的一个可访问媒介,ClassLoader提供了两个方法用于从装载的类路径中取得资源:
public URL getResource(String name);
public InputStream getResourceAsStream(String name);
这里name是资源的类路径,它是相对与“/”根路径下的位置。getResource得到的是一个URL对象来定位资源,而getResourceAsStream取得该资源输入流的引用保证程序可以从正确的位置抽取数据。
真正使用的不是ClassLoader的这两个方法,而是Class的getResource和getResourceAsStream方法,因为Class对象可以从你的类得到(如YourClass.class或YourClass.getClass()),而ClassLoader则需要再调用一次YourClass.getClassLoader()方法,但根据JDK文档的说法,Class对象的这两个方法其实是“委托”(delegate)给装载它的ClassLoader来做的,所以只需要使用Class对象的这两个方法就可以了。
在参考资料中有一篇老外写的文章比较深入介绍了从jar中装载资源的方法。
一个应用的例子
以下是在我写的一个小工具MSNHistoryCombiner中用到的一段代码,可以从jar中装载图片和文本信息。譬如,你的jar中根目录下有个img目录,里面放有一些图片,如img1.jpg,你可以这样调用
Utilities.getImageFromJar("/img/img1.jpg", YourClass.class);
注意必须这里是“/img/img1.jpg”而非“img/img1.jpg”。从jar中读文本资源也是类似方法调用getTextFromJar。
需要说明的是,这段代码也不是我原创的,是从一段别的代码中经过修改得到的,但原代码的来源忘记了,在这里向原作者表示感谢和歉意。
import java.awt.Image;
import java.awt.Toolkit;
import java.io.*;
public class ResourseReader {
public ResourseReader() {
}
public static Image getImageFromJar(String s, Class class1) {
Image image = null;
InputStream inputstream = class1.getResourceAsStream(s);
if(inputstream != null) {
ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream();
try {
byte abyte0[] = new byte[1024];
for(int i = 0; (i = inputstream.read(abyte0)) >= 0;) {
bytearrayoutputstream.write(abyte0, 0, i);
}
image = Toolkit.getDefaultToolkit().createImage(bytearrayoutputstream.toByteArray());
}
catch(IOException ioexception) {
ioexception.printStackTrace();
}
}
return image;
}
public static String getTextFromJar(String s, Class class1) {
String s1 = "";
InputStream inputstream = class1.getResourceAsStream(s);
if(inputstream != null) {
BufferedReader bufferedreader = new BufferedReader(new InputStreamReader(inputstream));
String s2;
try {
while((s2 = bufferedreader.readLine()) != null) {
s1 = s1 + s2 + "\n";
}
}
catch(IOException ioexception) {
ioexception.printStackTrace();
}
}
return s1;
}
}
从Jar中读取gif文件
在Java的程序发布中,很多人会选择采用二进制的jar的格式进行发布,怎么样读取Jar里面的资源呢?
主要是采用ClassLoader的下面几个方法来实现:
public URL getResource(String name);
public InputStream getResourceAsStream(String name)
public static InputStream getSystemResourceAsStream(String name)
public static URL getSystemResource(String name)
后两个方法可以看出是静态的方法,这几个方法都可以从Jar中读取图片资源,但是对与动画的gif文件,笔者在尝试过程中发现,存在一些差异。
String gifName为Gif文件在Jar中的相对路径。
(1)使用了两个静态方法
BufferedImage image=ImageIO.read(ClassLoader.getSystemResourceAsStream(gifName));
或者
Image image=Toolkit.getDefaultToolkit().getImage(ClassLoader.getSystemResource(gifName));
这两种方式可以成功地读取gif文件,但是对于gif动画,显示出来地是静态的。
(2)使用其他两个方法
Image image=Toolkit.getDefaultToolkit().getImage(this.getClass.getClassLoader().getResource(gifName));
再这种方式下动画可以正常显示了。
分享到:
相关推荐
"VC通过路径加载位图源码例子"是一个典型的编程任务,涉及到Windows API函数和MFC(Microsoft Foundation Classes)库的使用。下面将详细介绍这个过程中的关键知识点。 1. **Windows API**: Windows API提供了...
下面将详细探讨如何在UE4中实现动态加载资源以及涉及的相关路径信息。 1. **模块系统**:UE4中的资源是通过模块进行组织的,每个模块可以包含多个类、纹理、音频文件等。动态加载资源首先涉及到对模块的管理。当...
- **作用**:加载用户类路径(Classpath)上所指定的类库。 - **特点**:如果应用程序中没有自定义类加载器,通常就是使用此加载器。 #### 六、示例代码解析 以下是一个简单的示例代码,演示了如何获取不同级别...
### 使用Java类加载和类路径实现一个简单的在线购物网站 #### 概述 本文将详细介绍如何利用Java的类加载机制和类路径管理来构建一个简易的在线购物网站。该示例通过实现一个`ShoppingCart`类来管理用户的购物车...
自定义ClassLoader通常是为了满足特定的加载需求,例如从网络、数据库或非标准路径加载类。下面是一个简单的自定义ClassLoader的示例: ```java public class MyClassLoader extends ClassLoader { private String...
- 加载非标准路径的类:例如,从网络、数据库或本地的非标准目录加载类。 - 动态加载与热部署:在运行时加载新的类,无需重启应用,常用于插件系统。 - 安全隔离:不同加载器加载的类互不影响,可以用于实现安全...
3. **系统类加载器(Application ClassLoader)**:也称为应用类加载器,同样由Java编写,主要负责加载应用的类,即用户代码所在的`CLASSPATH`环境变量所指定的类路径。系统类加载器的父加载器是扩展类加载器。 类...
描述中提到的“在应用部署后,可找出是哪个类被加载了,在哪个目录或者jar中”,这通常是通过类加载工具的类路径分析功能实现的。这些工具可以帮助开发者追踪类的加载源,例如从哪个目录、哪个JAR文件或Web-INF/...
在传统的Java应用中,类通常是从硬盘上的类路径(ClassPath)或模块路径(ModulePath)中加载的。然而,随着开发模式的演变,如微服务、持续集成和持续部署(CI/CD)等,开发者们对更灵活的类加载机制有了需求。...
- `findSystemClass()`:尝试从本地系统路径加载类,如果找不到,会调用`defineClass()`来创建类对象。 理解类加载器的工作原理对于进行JVM优化、插件系统开发以及理解类的生命周期至关重要。类加载器的机制保证了...
应用程序类加载器也称为系统类加载器,它负责加载用户类路径(CLASSPATH)中的类。在WebLogic中,它还负责加载应用部署目录下的类。 5. **WebLogic特定类加载器** - **Domain类加载器**:每个WebLogic域都有一个...
3. **Application ClassLoader**(应用程序类加载器):也被称为系统类加载器,负责加载用户类路径(ClassPath)所指定的类。它的父类加载器为Extended ClassLoader。 #### 三、类加载过程详解 Java类的加载过程...
在这个例子中,`DiskClassLoader`接受一个类路径作为构造函数参数,然后在加载类时,它会从该路径下寻找`.class`文件。`findClass()`方法首先打开指定的文件,读取字节码数据,然后调用`defineClass()`方法将字节码...
4. 动态性:可以在运行时添加或移除类路径,支持热部署。 类加载的委托模型在Tomcat中也得到了体现。每个类加载器在尝试加载类时,会先委托给父类加载器,只有当父类加载器无法加载时,才会尝试自己加载。这种机制...
在我们的例子中,标题提到的"java 类从哪个jar包加载的",这通常涉及到类路径(ClassPath)的设置。类路径告诉JVM在哪里查找类文件。你可以通过`-cp`或`-classpath`命令行选项,或者在`JAVA_OPTS`环境变量中指定。...
3. **System ClassLoader(系统类加载器)**:也称为应用程序类加载器,它负责加载用户类路径(ClassPath)上指定的类。 每个类加载器都有其父类加载器,除了启动类加载器没有父加载器。当请求加载一个类时,如果...
4. Common ClassLoader:在Tomcat中,它是所有Web应用共享的类加载器,用于加载`common.loader`配置项指定的类路径。 5. WebApp ClassLoader:每个Web应用有自己的类加载器,它加载应用的`WEB-INF/classes`和`WEB-...
它的类路径通常由`java.class.path`系统属性指定。 #### 五、类加载过程详解 类加载的过程主要分为三个阶段:加载(Loading)、连接(Linking)和初始化(Initialization)。 1. **加载**(Loading): - 类加载...
- **应用程序类加载器(Application ClassLoader)**:也称为系统类加载器,负责加载用户类路径(ClassPath)中的类。 - **自定义类加载器(User-defined ClassLoader)**:用户可以根据需求编写自己的类加载器,...