`
阅读更多

在 开发java程序的过程中,我们经常要做的一件事就是获取资源。那么什么是资源呢?说白了,在计算机里那就是一堆数据。只是这堆数据对我们的java程 序有多种表现形式,一般来说有File,URL,InputStream等等。而单就文件这一项就有很多种:配置文件,java类文件,jps文件,图 片、css、js文件等等。面对这林林总总的资源,我们在设计一个读取资源的接口时,就需要针对不同形式的资源提供方法,这样就导致我们的接口还是与实际 的资源形式绑定在一起,未能完全的抽象。另外,在java程序中资源的存放位置也是各异的。有的存放在classpath中,有的存放在文件系统中,有的 存放在web应用中。而对于不同位置的资源,java程序获取这些资源的方法各有不同。

 

A、获取classpath中的资源:

URL url = this.getClass().getResource("resource_name");
URL url = this.getClass().getClassLoader().getResource("resource_name");
URL url = Thread.currentThread().getContextClassLoader().getResource("resource_name");

 那么在jdk中为什么又提供了三种方式来获取classpath下的资源呢?这其中是有些来头的。
第一行代码中是利用Class类的实例来获取,第二行代码是使用加载当前类的classloader来获取。看下jdk中的源代码会发现class类的实例最后还是委托加载他的classloader来获取资源的。

    public java.net.URL getResource(String name) {
        name = resolveName(name);
        ClassLoader cl = getClassLoader0();
        if (cl==null) {
            // A system class.
            return ClassLoader.getSystemResource(name);
        }
        return cl.getResource(name);
    }

 从上面的代码中可以看出,对于资源的加载并没有像类加载所采用的双亲委托机制。而是当前类的classloader不为null的情 况下先从当前类的 classloader中加载资源。而只有当前类的classloader为null的时候才从system classloader中去加载资源。这样可以方便我们自定义配置类覆盖一些默认配置。当然,j2se应用中如果没有特别定制classloader时, 我们自己写的类都是被system classloader加载的。到底利用class去获取资源和利用classloader去获取资源有什么区别呢?区别就在 resolveName(name)这个方法中。两种方式对于资源名称的表示方式不同。下面是一个简单的包结构,/表示类路径的根
/
|-com.cn.test
   |-Test.class
   |-test2.txt 
|-test1.txt

// 获取与当前类在同一个包下的资源
URL url1 = this.getClass().getResource("test2.txt");
// 获取com.cn.test包下的资源,需加/
URL url2 = this.getClass().getResource("/com/cn/test/test2.txt");
// 获取类路径根下的资源
URL url3 = this.getClass().getClassLoader().getResource("test1.txt");
// 获取包com.cn.test包下的资源
URL url4 = this.getClass().getResource("com/cn/test/test2.txt");

另外在servlet中:

this.getClass().getClassLoader().getResource("/").getPath();

 这将获取 到classes目录的全路径
例如 : E:/eclipseM9/workspace/tree/WEB-INF/classes/
 这个方法也可以在web环境里确定路径,比较好用


B、获取文件系统中的资源

// 1、获得File对象
File file = new File("test.txt");
// 2、获得File对象的字节流
InputStream in = new FileInputStream(file);

 值得注意的是在File的构造函数File(String name) 中的name参数可以是相对路径和绝对路径。相对路径是相对于System.getProperties("user.dir")的。


C、获取web应用中的资源

servletContext.getResourceAsStream(resource_name);

 

resource_names为相对于webroot的路径表示。例如获取web.xml,resource_name表示为"/WEB-INF/web.xml"

    面对上面介绍的各种资源表现形式和存放位置,难道java中就没有提供一个统一处理方式吗?有,java.net.URL。
从名称上来看 URL(Uniform Resource Locator) 统一资源定位器。看起来很好很强大。但很多时候使用它并不能定位到我们需要的资源。
    首先,它jdk中体统的URL能访问的协议非常有限(当然可以进行扩展,不过很麻烦);常用的有http,file,ftp等等。并没有提供对classpath和servletContext中的资源的获取方法。
    另外,它没有提供判断资源是否存在的方法。每次只有等我们真正去获取资源的时候抛出异常才能知道资源无法获取。
    其次,URL这个类的职责未划分清楚,既用来表示资源有用来获取其资源。

 

另外:

String path = getServletContext().getRealPath("/");

 将获取web项目的全路径
例如 :E:/eclipseM9/workspace/tree/
tree是我web项目的根目录

 

String webPath = ServletActionContext.getServletContext().getRealPath("/");

 将根据服务器的文件保存地址找到项目部署的绝对地址

 

以下内容

From :  http://blog.csdn.net/ruyanhai/archive/2007/11/07/1871663.aspx

 

一般情况下,我们都使用相对路径来获取资源,这样的灵活性比较大.

 

比如当前类为com/bbebfe/Test.class

 

而图像资源比如sample.gif应该放置在com/bbebfe/sample.gif

 

而如果这些图像资源放置在icons目录下,则应该是com/bbebfe/icons/sample.gif

 

通过当前类文件的路径获取资源主要有如下几种方式:

 

· 假设当前类为com.bbebfe.Test

 

· 包所在的文件夹为bin

String imageName = "icons/sample.gif"

 

1, 通过Class.getResource()定位类路径下的资源(bin/com/bbebfe/icons/sample.gif)

 

Class clazz = this.getClass();

 

URL url = clazz.getResource(imageName);

 

 

2,通过ClassLoader.getResource()定位包的根目录下的资源(bin/icons/sample.gif)

 

Class clazz = this.getClass();

URLClassLoader loader = (URLClassLoader)clazz.getClassLoader();

URL url = loader.getResource(imageName);

 3, 通过ClassLoader.findResource()提供自己定制的方式定位资源

URL url = loader.findResource(imageName);

那么这三种方法有那些区别, 我们应该在何时使用哪种方法呢?

 

· Class.getResource() 方法

 

该方法实际通过该ClassClass LoadergetResource()方法来获得资源, 在调用ClassLoadergetResource()方法之前, Class.getResource()方法会对资源名称做一定的处理,构建一个该资源的绝对名称(absolute name, 大意是:

 

       如果资源名称以'/'('/u002f') 开始, 则资源的绝对名称是'/'以后的部分.

 

              如果imageName"/icons/sample.gif", 则在这里会变成"icons/sample.gif"

 

       否则对于其他情况, 绝对名称将是如下形式(给资源名称的前面加上modified_package_name/):
              modified_package_name/resource_name (
修正的包名称/资源名称)

 

其中修正的包名称含义是将当前对象所在的包名称中的'.'('/u002e')替换为'/'

 

如果ClassLoader.getResource()方法返回一个值为nullURL, Class.getResource()方法最终会将资源请求交给ClassLoader.getSystemResource(java.lang.String).

 

· ClassLoader.getResource() 方法

 

该对资源进行查找, 资源的名称是以'/'分隔的路径, 这个方法首先查找自己的父亲ClassLoader, 由自己的父ClassLoader来查找资源(实际上, 如果父亲的父亲不是空, 则父亲仍会向上提交查找请求). 如果自己的父ClassLoadernull, 则查找Java虚拟机中内建的class loader, 并将资源请求提交给它们, 如果这些操作都失败了, ClassLoader会调用自己的findResource()方法来查找资源.

 

· ClassLoader.findResource() 方法

 

该方法在内部查找指定的资源, 如果你实现了自己的Class Loader,则应该重载这个方法以自己特定的方式来查找类文件和资源.

 

 

 

通过以上的总结, 我们可以看到三点.

 

1, 无论是getResource(), 还是findResource(), 这些方法都只是资源的定位方法, 最终都只是返回一个URL, 只是对资源的定位而已, 我们随后应通过自己的方法来读取这些资源. 而在ClassClassLoader中还定义的有getResourceAsStream方法, 该方法是getResource的增强版, 这里就不介绍了.

 

 

2,如果需要以类为相对路径查找资源, 则应该调用Class.getResource()方法, 不要直接调用ClassLoader.getResource()方法. 另外, 除非是你自己定义了ClassLoader并重载了findResource方法,否则也不要直接调用ClassLoader.findResource方法, 因为在Class.getResource()方法中会对资源名称作一定的处理, 这在上面介绍了, 下面举个实例:

 

       假设我的当前类在Eclipse工程Database, 类所在的包是com.bbebfe.test, icons目录放在bin/com/bbebfe/test/目录下, 我需要得到icons/sample.gif文件的URL, 则调用this.getClass().getResource()得到的URL:

 

       file:/E:/MyLife/MyProjects/Eclipse3.2/Database/bin/com/bbebfe/test/icons/disremove.gif

 

 

 

3, 有时候我们希望某个jar库的图像资源在同一个icons下统一管理, 而不是为每个包下面的Class建一个icons, 也就是说需要以库为相对路径来查找资源, 此时则应该调用ClassLoader.getResource()方法, 举个例子:

 

·某个工程有如下的包结构:

 

       com.bbebfe.ui

 

       com.bbebfe.test

 

       com.bbebfe.database

 

·如果以类为相对路径, 则在每个包下都必须建立一个icons目录, 并放置相应的资源文件. 如下:

 

       com.bbebfe.ui/icons/...

 

       com.bbebfe.test/icons/...

 

       com.bbebfe.database/icons/...

 

·而我们可能希望在根目录下放置一个icons目录, 把所有资源放置在这里管理, 这样还可以防止资源的重复. 就是如下形式

 

       com.bbebfe.ui

 

       com.bbebfe.test

 

       com.bbebfe.database

 

       icons/sample.gif ...

 

       则此时我们应该调用ClassLoader.getResource方法, 由于它没有对资源名称作处理, 也就是说没有将修正的包名添加到资源名称前, 所以它会在类所在的包的根下去查找资源.(运行java程序的语法是java com.bbebfe.ui.Test, 所以根目录com目录的上级目录).

 

 

 

最后, Java中对资源进行定位的方法有很多种, Eclipse源代码中还有如下一段定位文件资源的代码, 还没有时间研究:

 

ProtectionDomain domain = Main.class.getProtectionDomain();

CodeSource source = null;

URL result = null;

if (domain != null)

source = domain.getCodeSource();//获得code source

if (source != null)

      result = source.getLocation();//获得URL

          

String path = decode(result.getFile());//

// normalize to not have leading / so we can check the form

File file = new File(path);

path = file.toString().replace('//', '/');

// create a file URL (via File) to normalize the form (e.g., put

// the leading / on if necessary)

path = new File(path).toURL().getFile();

 

 

 转载请注明出处http://lucien-zzy.iteye.com/admin/blogs/2001768

2
0
分享到:
评论
1 楼 kingcs 2014-01-10  
不错,学习了

相关推荐

    Nodejs 实现磁力链接获取 DHT BT爬虫 磁力链接解析 种子解析 资源搜索

    本文将深入探讨使用Node.js实现磁力链接获取、DHT(分布式哈希表)爬虫、磁力链接解析、种子解析以及资源搜索的相关知识点。 首先,我们来了解磁力链接。磁力链接是一种基于信息哈希值的链接方式,它不依赖于特定的...

    pe文件解析:读取pe信息获取文件资源(源码)

    这篇源码主要涉及的是如何解析PE文件并获取其中的资源信息。在Windows系统中,无论是可执行程序(EXE)、动态链接库(DLL)还是驱动程序(SYS),它们都遵循PE文件格式。下面将详细讨论PE文件结构以及解析过程。 1....

    Node.js-Nonejs实现磁力链接获取DHTBT爬虫磁力链接解析种子解析资源搜索

    在给定的标题和描述中,我们关注的是使用 Node.js 实现磁力链接获取、DHT BT 爬虫、磁力链接解析、种子解析以及资源搜索的相关技术。 1. **磁力链接**:磁力链接是一种去中心化的文件链接方式,它不依赖于具体的...

    【4333】PHP素材资源解析平台源码V8.0.rar

    2. **素材资源解析**:平台的核心功能是解析不同素材网站的URL,通过技术手段模拟用户访问,获取并下载资源。这涉及到HTML解析(可能使用DOM或BeautifulSoup等库)、网络请求(如cURL)以及可能的反爬虫策略分析。 ...

    java解析资源文件

    在Java编程中,解析资源文件是一项常见的任务,它涉及到读取和操作项目中的文本、配置、图片等非代码数据。本教程将深入讲解如何在Java中处理资源文件,以及使用jbom解析工具的相关知识。 首先,理解资源文件的定位...

    Json解析获取网络图片

    综上所述,"Json解析获取网络图片"涉及到的知识点涵盖了JSON解析、网络请求、图片加载库的使用、权限管理、异步编程以及内存优化等多个方面。通过学习和实践这些知识点,开发者可以构建出高效、用户体验良好的...

    PE资源图标解析

    3. 解析组图标目录(ICONGROUP)以获取图标实例的列表。 4. 对于每个图标实例,根据其RVA定位到图标数据,并解析ICONDIRENTRY。 5. 读取BITMAPINFOHEADER和位图数据,转换成可见的图像格式。 在实践中,我们可以...

    android 动态解析获取json数据的键值对

    在Android开发中,有时我们需要从服务器获取JSON数据并解析它以展示在应用中。这个"android 动态解析获取json数据的键值对"的项目就是针对这种情况的一个实例,主要展示了如何在Eclipse环境下,不预先创建JSON键值...

    115资源地址解析工具

    需要注意的是,使用这类工具可能存在一定的风险,比如隐私泄露、病毒感染等,因此,确保从可信赖的来源获取解析工具,并保持软件的更新,以降低潜在的安全隐患。 此外,115网盘的政策可能会不断变化,这可能会影响...

    C#获取网络资源源码--VS2010--获取糗事百科

    综上所述,通过C#和VS2010,我们可以编写程序获取并解析网络资源,例如“糗事百科”的内容。这涉及到HTTP请求、响应处理以及HTML解析等多个环节,而C#强大的类库为我们提供了实现这些功能的强大工具。在实际应用中,...

    调用资源站可二次解析的解析

    我们可以构建一个简单的场景:这是一个使用PHP开发的小型网站,提供API服务(api.php),可能有一个自定义的CSS处理器(css.php),并且允许通过`index.php`处理带参数的URL请求来获取或解析远程资源。此外,网站...

    蓝奏云直链获取在线解析网站源码 蓝奏云链接解析 本地API接口

    总的来说,蓝奏云直链获取在线解析网站源码提供了一个高效且简便的方式来获取云存储资源的直接下载链接,对于开发者和普通用户来说都是一个实用的工具。通过理解和运用这个源码,可以进一步了解网络请求、API接口...

    百度文库资源解析原理与实现讲解.doc

    首先,解析百度文库资源的关键在于获取文档的基本信息。以示例文档`http://wenku.baidu.com/view/9a2feb165f0e7cd18425363a.html`为例,我们需要下载这个网页内容,从中提取出`DOC_INFO`字段。该字段包含了文档的...

    sax解析xml尤其是获取元素的值或者内容

    本文将深入探讨如何使用SAX解析XML并获取元素的值或内容。 首先,SAX解析器以流式方式读取XML文档,当遇到文档的不同部分时,会触发相应的事件,如开始文档、开始元素、结束元素等。开发者可以注册事件处理器来响应...

    网络json获取与解析

    在网络json获取过程中,通常使用HTTP GET方法请求服务器上的资源,其中包括JSON格式的数据。 2. **JSON格式**:JSON是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。它基于JavaScript的...

    解析apk资源的aar包,并附带关键代码

    开发者可以根据需要扩展这些基础功能,以实现更复杂的解析逻辑,例如获取应用权限、解析布局文件、读取图片或音频资源等。 在实际开发中,解析APK的用途多种多样,包括但不限于逆向工程、安全分析、性能优化和自动...

    android获取网络资源

    在Android平台上,获取网络资源是开发过程中不可或缺的一部分。这涵盖了从加载网页到下载图片、音频、视频等各类数据。...开发者可以根据项目需求和性能要求,选择合适的工具和策略,实现高效、稳定的网络资源获取。

Global site tag (gtag.js) - Google Analytics