Java路径问题讨论

Class.getResource vs ClassLoader.getResource

这两个方法还是略有区别的, 以前一直不加以区分,直到今天发现要写这样的代码的时候运行
错误, 才把这个问题澄清了一下。

基本上,两个都可以用于从 classpath 里面进行资源读取, classpath包含classpath中的路径
和classpath中的jar。

两个方法的区别是资源的定义不同, 一个主要用于相对与一个object取资源,而另一个用于取相对于classpath的
资源,用的是绝对路径。

在使用Class.getResourceAsStream 时, 资源路径有两种方式, 一种以 / 开头,则这样的路径是指定绝对
路径, 如果不以 / 开头, 则路径是相对与这个class所在的包的。

在使用ClassLoader.getResourceAsStream时, 路径直接使用相对于classpath的绝对路径。

举例,下面的三个语句,实际结果是一样的:
com.explorers.Test.class.getResourceAsStream("abc.jpg")
= com.explorers.Test.class.getResourceAsStream("/com/explorers/abc.jpg")
= ClassLoader.getResourceAsStream("com/explorers/abc.jpg")

主题:资源获取:

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

Java代码
  1. URLurl=this.getClass().getResource("resource_name");
  2. URLurl=this.getClass().getClassLoader().getResource("resource_name");
  3. URLurl=Thread.currentThread().getContextClassLoader().getResource("resource_name");
 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来获取资源的。

Java代码
  1. publicjava.net.URLgetResource(Stringname){
  2. name=resolveName(name);
  3. ClassLoadercl=getClassLoader0();
  4. if(cl==null){
  5. //Asystemclass.
  6. returnClassLoader.getSystemResource(name);
  7. }
  8. returncl.getResource(name);
  9. }
 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

Java代码
  1. //获取与当前类在同一个包下的资源
  2. URLurl1=this.getClass().getResource("test2.txt");
  3. //获取com.cn.test包下的资源,需加/
  4. URLurl2=this.getClass().getResource("/com/cn/test/test2.txt");
  5. //获取类路径根下的资源
  6. URLurl3=this.getClass().getClassLoader().getResource("test1.txt");
  7. //获取包com.cn.test包下的资源
  8. URLurl4=this.getClass().getResource("com/cn/test/test2.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");


而第三利用当前线程的contextClassLoader来获取资源的解释可以参考我的另一篇
B、获取文件系统中的资源

Java代码
  1. //1、获得File对象
  2. Filefile=newFile("test.txt");
  3. //2、获得File对象的字节流
  4. InputStreamin=newFileInputStream(file);
 // 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应用中的资源

Java代码
  1. servletContext.getResourceAsStream(resource_name);
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这个类的职责未划分清楚,既用来表示资源有用来获取其资源。

===============================================

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() 方法

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

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

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

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

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

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

· ClassLoader.getResource() 方法

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

· ClassLoader.findResource() 方法

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

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

1, 无论是getResource(), 还是findResource(), 这些方法都只是资源的定位方法, 最终都只是返回一个URL, 只是对资源的定位而已, 我们随后应通过自己的方法来读取这些资源. 而在Class和ClassLoader中还定义的有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();

前言
Java的路径问题,非常难搞。最近的工作涉及到创建和读取文件的工作,这里我就给大家彻底得解决 Java路径问题。
我编写了一个方法,比ClassLoader.getResource(String 相对路径)方法的能力更强。它可以接受“../”这样的参数,允许我们用 相对路径来定位classpath外面的资源。这样,我们就可以使用相对于classpath的路径,定位所有位置的资源!
Java路径
Java中使用的路径,分为两种:绝对路径和 相对路径。具体而言,又分为四种:
一、URI形式的绝对资源路径
如:file:/D:/ Java/eclipse32/workspace/jbpmtest3/bin/aaa.b
URL是URI的特例。URL的前缀/协议,必须是 Java认识的。URL可以打开资源,而URI则不行。
URL和URI对象可以互相转换,使用各自的toURI(),toURL()方法即可!
二、本地系统的绝对路径
D:/ Java/eclipse32/workspace/jbpmtest3/bin/aaa.b
Java.io包中的类,需要使用这种形式的参数。
但是,它们一般也提供了URI类型的参数,而URI类型的参数,接受的是URI样式的String。因此,通过URI转换,还是可以把URI样式的绝对路径用在 Java.io包中的类中。
三、相对于classpath的相对路径
如:相对于
file:/D:/ Java/eclipse32/workspace/jbpmtest3/bin/这个路径的 相对路径。其中,bin是本项目的classpath。所有的 Java源文件编译后的.class文件复制到这个目录中。
四、相对于当前用户目录的相对路径
就是相对于System.getProperty("user.dir")返回的路径。
对于一般项目,这是项目的根路径。对于 JavaEE服务器,这可能是服务器的某个路径。这个并没有统一的规范!
所以,绝对不要使用“相对于当前用户目录的 相对路径”。然而:
默认情况下,Java.io 包中的类总是根据当前用户目录来分析相对路径名。此目录由系统属性 user.dir 指定,通常是 Java 虚拟机的调用目录。
这就是说,在使用Java.io包中的类时,最好不要使用相对路径。否则,虽然在J2SE应用程序中可能还算正常,但是到了J2EE程序中,一定会出问题!而且这个路径,在不同的服务器中都是不同的!
相对路径最佳实践
推荐使用相对于当前classpath的相对路径
因此,我们在使用 相对路径时,应当使用相对于当前classpath的 相对路径
ClassLoader类的getResource(String name), getResourceAsStream(String name)等方法,使用相对于当前项目的classpath的相对路径来查找资源。
读取属性文件常用到的ResourceBundle类的getBundle(String path)也是如此。
通过查看ClassLoader类及其相关类的源代码,我发现,它实际上还是使用了URI形式的绝对路径。通过得到当前classpath的URI形式的绝对路径,构建了 相对路径的URI形式的绝对路径。(这个实际上是猜想,因为JDK内部调用了SUN的源代码,而这些代码不属于JDK,不是开源的。)
相对路径本质上还是绝对路径
因此,归根结底,Java本质上只能使用绝对路径来寻找资源。所有的相对路径寻找资源的方法,都不过是一些便利方法。不过是API在底层帮助我们构建了绝对路径,从而找到资源的!
得到classpath和当前类的绝对路径的一些方法
下面是一些得到classpath和当前类的绝对路径的一些方法。你可能需要使用其中的一些方法来得到你需要的资源的绝对路径。
1,FileTest.class.getResource("")
得到的是当前类FileTest.class文件的URI目录。不包括自己!
如: file:/D:/Java/eclipse32/workspace/jbpmtest3/bin/com/test/
2,FileTest.class.getResource("/")
得到的是当前的classpath的绝对URI路径。
如: file:/D:/Java/eclipse32/workspace/jbpmtest3/bin/
3,Thread.currentThread().getContextClassLoader().getResource("")
得到的也是当前ClassPath的绝对URI路径。
如: file:/D:/Java/eclipse32/workspace/jbpmtest3/bin/
4,FileTest.class.getClassLoader().getResource("")
得到的也是当前ClassPath的绝对URI路径。
如: file:/D:/Java/eclipse32/workspace/jbpmtest3/bin/
5,ClassLoader.getSystemResource("")
得到的也是当前ClassPath的绝对URI路径。
如: file:/D:/Java/eclipse32/workspace/jbpmtest3/bin/
我推荐使用Thread.currentThread().getContextClassLoader().getResource("")来得到当前的classpath的绝对路径的URI表示法。
Web应用程序中资源的寻址
上文中说过,当前用户目录,即相对于System.getProperty("user.dir")返回的路径。
对于 JavaEE服务器,这可能是服务器的某个路径,这个并没有统一的规范!
而不是我们发布的Web应用程序的根目录!
这样,在Web应用程序中,我们绝对不能使用相对于当前用户目录的 相对路径
在Web应用程序中,我们一般通过ServletContext.getRealPath("/")方法得到Web应用程序的根目录的绝对路径。
这样,我们只需要提供相对于Web应用程序根目录的路径,就可以构建出定位资源的绝对路径。
这是我们开发Web应用程序时一般所采取的策略。
通用的相对路径解决办法
Java中各种 相对路径非常多,不容易使用,非常容易出错。因此,我编写了一个便利方法,帮助更容易的解决 相对路径问题。
Web应用程序中使用JavaSE运行的资源寻址问题
JavaSE程序中,我们一般使用classpath来作为存放资源的目的地。但是,在Web应用程序中,我们一般使用classpath外面的WEB-INF及其子目录作为资源文件的存放地。
在Web应用程序中,我们一般通过ServletContext.getRealPath("/")方法得到Web应用程序的根目录的绝对路径。这样,我们只需要提供相对于Web应用程序根目录的路径,就可以构建出定位资源的绝对路径。
Web应用程序,可以作为Web应用程序进行发布和运行。但是,我们也常常会以 JavaSE的方式来运行Web应用程序的某个类的main方法。或者,使用JUnit测试。这都需要使用 JavaSE的方式来运行。
这样,我们就无法使用ServletContext.getRealPath("/")方法得到Web应用程序的根目录的绝对路径。
而JDK提供的ClassLoader类,
它的getResource(String name), getResourceAsStream(String name)等方法,使用相对于当前项目的classpath的相对路径来查找资源。
读取属性文件常用到的ResourceBundle类的getBundle(String path)也是如此。
它们都只能使用 相对路径来读取classpath下的资源,无法定位到classpath外面的资源。
Classpath外配置文件读取问题
如,我们使用测试驱动开发的方法,开发Spring、Hibernate、iBatis等使用配置文件的Web应用程序,就会遇到问题。
尽管Spring自己提供了FileSystem(也就是相对于user,dir目录)来读取Web配置文件的方法,但是终究不是很方便。而且与Web程序中的代码使用方式不一致!
至于Hibernate,iBatis就更麻烦了!只有把配置文件移到classpath下,否则根本不可能使用测试驱动开发!
这怎么办?
通用的相对路径解决办法
面对这个问题,我决定编写一个助手类 ClassLoaderUtil,提供一个便利方法[ public static URL getExtendResource(String relativePath)]。在Web应用程序等一切 Java程序中,需要定位classpath外的资源时,都使用这个助手类的便利方法,而不使用Web应用程序特有的ServletContext.getRealPath("/")方法来定位资源。
利用classpath的绝对路径,定位所有资源
这个便利方法的实现原理,就是“利用classpath的绝对路径,定位所有资源”。
ClassLoader类的getResource("")方法能够得到当前classpath的绝对路径,这是所有 Java程序都拥有的能力,具有最大的适应性!
而目前的JDK提供的ClassLoader类的getResource(String 相对路径)方法,只能接受一般的 相对路径。这样,使用ClassLoader类的getResource(String 相对路径)方法就只能定位到classpath下的资源。
如果,它能够接受“../”这样的参数,允许我们用相对路径来定位classpath外面的资源,那么我们就可以定位位置的资源!
当然,我无法修改ClassLoader类的这个方法,于是,我编写了一个助手类ClassLoaderUtil类,提供了[ public static URL getExtendResource(String relativePath)]这个方法。它能够接受带有“../”符号的 相对路径,实现了自由寻找资源的功能。
通过相对classpath路径实现自由寻找资源的助手类的源代码:
import Java.io.IOException;
import Java.io.InputStream;
import Java.net.MalformedURLException;
import Java.net.URL;
import Java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* @author 沈东良 shendl_s@hotmail.com
* Nov 29, 2006 10:34:34 AM
* 用来加载类,classpath下的资源文件,属性文件等。
* getExtendResource(String relativePath) 方法,可以使用../符号来加载classpath外部的资源。
*/
publicclass ClassLoaderUtil {
privatestatic Log log =LogFactory.getLog(ClassLoaderUtil. class );
/**
* Thread.currentThread().getContextClassLoader().getResource("")
*/
/**
* 加载Java类。 使用全限定类名
* @param className
* @return
*/
publicstatic Class loadClass(String className) {
try {
return getClassLoader().loadClass(className);
} catch (ClassNotFoundException e) {
thrownew RuntimeException( "class not found '" +className+ "'" , e);
}
}
/**
* 得到类加载器
* @return
*/
publicstatic ClassLoader getClassLoader() {
return ClassLoaderUtil. class .getClassLoader();
}
/**
* 提供相对于classpath的资源路径,返回文件的输入流
* @param relativePath 必须传递资源的相对路径。是相对于classpath的路径。如果需要查找classpath外部的资源,需要使用../来查找
* @return 文件输入流
* @throws IOException
* @throws MalformedURLException
*/
publicstatic InputStream getStream(String relativePath) throws MalformedURLException, IOException {
if (!relativePath.contains( "../" )){
return getClassLoader().getResourceAsStream(relativePath);
} else {
return ClassLoaderUtil.getStreamByExtendResource(relativePath);
}
}
/**
*
* @param url
* @return
* @throws IOException
*/
publicstatic InputStream getStream(URL url) throws IOException{
if (url!= null ){
return url.openStream();
} else {
returnnull ;
}
}
/**
*
* @param relativePath 必须传递资源的相对路径。是相对于classpath的路径。如果需要查找classpath外部的资源,需要使用../来查找
* @return
* @throws MalformedURLException
* @throws IOException
*/
publicstatic InputStream getStreamByExtendResource(String relativePath) throws MalformedURLException, IOException{
return ClassLoaderUtil.getStream(ClassLoaderUtil.getExtendResource(relativePath));
}
/**
* 提供相对于classpath的资源路径,返回属性对象,它是一个散列表
* @param resource
* @return
*/
publicstatic Properties getProperties(String resource) {
Properties properties = new Properties();
try {
properties.load(getStream(resource));
} catch (IOException e) {
thrownew RuntimeException( "couldn't load properties file '" +resource+ "'" , e);
}
return properties;
}
/**
* 得到本Class所在的ClassLoader的Classpat的绝对路径。
* URL 形式的
* @return
*/
publicstatic String getAbsolutePathOfClassLoaderClassPath(){
ClassLoaderUtil. log .info(ClassLoaderUtil.getClassLoader().getResource( "" ).toString());
return ClassLoaderUtil.getClassLoader().getResource( "" ).toString();
}
/**
*
* @param relativePath 必须传递资源的相对路径。是相对于classpath的路径。如果需要查找classpath外部的资源,需要使用../来查找
* @return 资源的绝对URL
* @throws MalformedURLException
*/
publicstatic URL getExtendResource(String relativePath) throws MalformedURLException{
ClassLoaderUtil. log .info( " 传入的相对路径:" +relativePath) ;
//ClassLoaderUtil.log.info(Integer.valueOf(relativePath.indexOf("../"))) ;
if (!relativePath.contains( "../" )){
return ClassLoaderUtil.getResource(relativePath);
}
String classPathAbsolutePath=ClassLoaderUtil.getAbsolutePathOfClassLoaderClassPath();
if (relativePath.substring(0, 1).equals( "/" )){
relativePath=relativePath.substring(1);
}
ClassLoaderUtil. log .info(Integer.valueOf(relativePath.lastIndexOf( "../" ))) ;
String wildcardString=relativePath.substring(0,relativePath.lastIndexOf( "../" )+3);
relativePath=relativePath.substring(relativePath.lastIndexOf( "../" )+3);
int containSum=ClassLoaderUtil.containSum(wildcardString, "../" );
classPathAbsolutePath= ClassLoaderUtil.cutLastString(classPathAbsolutePath, "/" , containSum);
String resourceAbsolutePath=classPathAbsolutePath+relativePath;
ClassLoaderUtil. log .info( " 绝对路径:" +resourceAbsolutePath) ;
URL resourceAbsoluteURL= new URL(resourceAbsolutePath);
return resourceAbsoluteURL;
}
/**
*
* @param source
* @param dest
* @return
*/
privatestaticint containSum(String source,String dest){
int containSum=0;
int destLength=dest.length();
while (source.contains(dest)){
containSum=containSum+1;
source=source.substring(destLength);
}
return containSum;
}
/**
*
* @param source
* @param dest
* @param num
* @return
*/
privatestatic String cutLastString(String source,String dest, int num){
// String cutSource=null;
for ( int i=0;i<num;i++){
source=source.substring(0, source.lastIndexOf(dest, source.length()-2)+1);
}
return source;
}
/**
*
* @param resource
* @return
*/
publicstatic URL getResource(String resource){
ClassLoaderUtil. log .info( " 传入的相对于classpath的路径:" +resource) ;
return ClassLoaderUtil.getClassLoader().getResource(resource);
}
/**
* @param args
* @throws MalformedURLException
*/
publicstaticvoid main(String[] args) throws MalformedURLException {
//ClassLoaderUtil.getExtendResource("../spring/dao.xml");
//ClassLoaderUtil.getExtendResource("../../../src/log4j.properties");
ClassLoaderUtil.getExtendResource( "log4j.properties" );
System. out .println(ClassLoaderUtil.getClassLoader().getResource( "log4j.properties" ).toString());
}
}
后记
ClassLoaderUtil类的public static URL getExtendResource(String relativePath),虽然很简单,但是确实可以解决大问题。
不过这个方法还是比较简陋的。我还想在未来有空时,进一步增强它的能力。比如,增加Ant风格的匹配符。用**代表多个目录,*代表多个字符,?代表一个字符。达到Spring那样的能力,一次返回多个资源的URL,进一步方便大家开发。
总结:
1,尽量不要使用相对于System.getProperty("user.dir")当前用户目录的 相对路径。这是一颗定时,随时可能要你的命。
2,尽量使用URI形式的绝对路径资源。它可以很容易的转变为URI,URL,File对象。
3,尽量使用相对classpath的 相对路径。不要使用绝对路径。使用上面ClassLoaderUtil类的public static URL getExtendResource(String relativePath)方法已经能够使用相对于classpath的 相对路径定位所有位置的资源。
4,绝对不要使用硬编码的绝对路径。因为,我们完全可以使用ClassLoader类的getResource("")方法得到当前classpath的绝对路径。
使用硬编码的绝对路径是完全没有必要的!它一定会让你死的很难看!程序将无法移植!
如果你一定要指定一个绝对路径,那么使用配置文件,也比硬编码要好得多!
当然,我还是推荐你使用程序得到classpath的绝对路径来拼资源的绝对路径!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值