您的位置:首页 > 编程语言 > Java开发

java文件路径操作详细

2010-09-22 13:36 405 查看
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应用程序时一般所采取的策略。





 
 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


*Nov29,2006 10:34:34AM


*用来加载类,classpath下的资源文件,属性文件等。


*getExtendResource(StringrelativePath)方法,可以使用../符号来加载
classpath外部的资源。


*/


publicclass ClassLoaderUtil {

 
privatestatic Log log=LogFactory.getLog(ClassLoaderUtil.class
);

 /**


 
*Thread.currentThread().getContextClassLoader().getResource("")


 */




 /**


 
*加载Java类。 使用全限定类名


 
*@paramclassName


 
*@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的资源路径,返回文件的输入流


 *@paramrelativePath必须传递资源的相对路径。是相对于classpath的路径。如果需要查找
classpath外部的资源,需要使用 ../来查找


 *@return 文件输入流


 *@throwsIOException


 *@throwsMalformedURLException


 */


 
publicstatic InputStream getStream(String relativePath) throws
MalformedURLException, IOException {

 
 if
(!relativePath.contains(
"../"
)){

   return
getClassLoader().getResourceAsStream(relativePath);

 
 }else
{

 
  return
ClassLoaderUtil.getStreamByExtendResource(relativePath);

 
 }

 }

 /**


 
*


 *@paramurl


 *@return


 *@throwsIOException


 */


 
publicstatic InputStream getStream(URL url) throws
IOException{

 
 if
(url!=
null
){

 
  return
url.openStream();

 
 }else
{

 
  returnnull;

  }

 }

 /**


 
*


 
*@paramrelativePath必须传递资源的相对路径。是相对于classpath的路径。如果需要查找classpath外部的资源,需要使
用 ../来查找


 *@return


 *@throwsMalformedURLException


 *@throwsIOException


 */


 
publicstatic InputStream getStreamByExtendResource(String relativePath) throws
MalformedURLException, IOException{

 
 return
ClassLoaderUtil.getStream(ClassLoaderUtil.getExtendResource(relativePath));

 
}



 /**


 *提供相对于classpath的资源路径,返回属性对象,它是一个散列表


 *@paramresource


 *@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();

 
}

 /**


 *


 
*@paramrelativePath 必须传递资源的相对路径。是相对于classpath的路径。如果需要查找classpath外部的资源,需要
使 用../来查找


 *@return资
源的绝对URL


 
*@throwsMalformedURLException


 */


 
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;

 
}

 /**


 *


 
*@paramsource


 
*@paramdest


 
*@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;

 
}

 /**


 *


 
*@paramsource


 
*@paramdest


 
*@paramnum


 
*@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;

 
}

 /**


 *


 
*@paramresource


 
*@return


 */


 
publicstatic URL getResource(String resource){

 
 ClassLoaderUtil.log.info("传入的相对于classpath的路径:"
+resource) ;

 
 return
ClassLoaderUtil.getClassLoader().getResource(resource);

 
}

 /**


 *@paramargs


 *@throwsMalformedURLException


 */


 
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的绝对路径来拼资源的绝对路径!



1
.如何获得当前文件路径


用:

字符串类型:System.getProperty("user.dir"
);


合:

package
com.zcjl.test.base;

import
java.io.File;

public

class
Test {

public

static

void
main(String[] args)
throws
Exception {

System.out.println(

Thread.currentThread().getContextClassLoader().getResource(""
));

System.out.println(Test.class
.getClassLoader().getResource(
""
));

System.out.println(ClassLoader.getSystemResource(""
));

System.out.println(Test.class
.getResource(
""
));

System.out.println(Test.class
.getResource(
"/"
));



System.out.println(new
File(
""
).getAbsolutePath());

System.out.println(System.getProperty("user.dir"
));

}

}

file:/E:/workSpace/javaTest/target/classes/

file:/E:/workSpace/javaTest/target/classes/

file:/E:/workSpace/javaTest/target/classes/

file:/E:/workSpace/javaTest/target/classes/javaAPI/

file:/E:/workSpace/javaTest/target/classes/

E:/workSpace/javaTest

E:/workSpace/javaTest



2
.Web服务中

(1
).Weblogic

WebApplication
的系统文件根目录是你的weblogic安装所在根目录。

例如:如果你的weblogic安装在
c:/bea/weblogic700.....

那么,你的文件根路径就是c:/.


以,有两种方式能够让你访问你的服务器端的文件:

a.使用绝对路径:


如将你的参数文件放在c:/yourconfig/yourconf.properties,

直接使
用 new
FileInputStream(
"/yourconfig/yourconf.properties"
);

b.
使用相对路径:

相对路径的根目录就是你的webapplication的根路径,即WEB-INF的
上一级目录,将你的参数文件放在yourwebapp/yourconfig/yourconf.properties,


样使用:

new
FileInputStream(
"yourconfig/yourconf.properties"
);


两种方式均可,自己选择。

(2
).Tomcat


类中输出System.getProperty("user.dir"
);显示的
是%Tomcat_Home%/bin

(3
).Resin


是你的JSP放的相对路径,是JSP引擎执行这个JSP编译成SERVLET

的路径为根.比如用新建
文件法测试File f = new
File(
"a.htm"
);

这个
a.htm在resin的安装目录下

(4
).
如何读相对路径哪?

在Java文件中getResource或
getResourceAsStream均可

例:getClass().getResourceAsStream(filePath);//filePath可以是"/filename",这里的/代表web发布根路径下WEB-INF
/classes


也可以
getClass().getClassLoader().getResourceAsStream(filePath)//filePath不是带“/”的


(5
).获得文件真实路径

string file_real_path=request.getRealPath("mypath/filename"
);


常使用request.getRealPath("/"
);

4
.遗留问题

目前new
FileInputStream()只会使用绝对路径,相对



InputStream in1 = new
FileInputStream(
"abc1.properties"
);
// 相对路径


InputStream in2 = new
FileInputStream(
"/abc2.properties"
);
// 绝对路径,E盘下


InputStream in3 = new
FileInputStream(
"e://abc3.properties"
); //相对路径

5
.按Java文件类型分类读取配置文件

配 置
文件是应用系统中不可缺少的,可以增加程序的灵活性。java.util.Properties是从jdk1.2

有的类,一直到现在都支持load ()方法,jdk1.
4
以后
save(output,string) ->store(output,string)。如果只是单纯的读,根本不存在烦恼的问题。web层可以
通过 Thread.currentThread().getContextClassLoader().

getResourceAsStream("xx.properties"
) 获取;

Application
可以通过new
FileInputStream(
"xx.properties"
);直接在classes一级获取。关键是有时我们需要通过
web修改配置文件,我们不 能将路径写死了。经过测试觉得有以下心得:

1
.servlet中读写。如果运用Struts 或者Servlet可以直接在初始化参数中
配置,调用时根据servlet的getRealPath(
"/"
)
获取真实路径,再根据String file =
this
.servlet.getInitParameter(
"abc"
);获取相对的WEB-INF的相对路径。

例:

InputStream input = Thread.currentThread().getContextClassLoader().

getResourceAsStream("abc.properties"
);

Properties prop = new
Properties();

prop.load(input);

input.close();

OutputStream out = new
FileOutputStream(path);

prop.setProperty("abc"
, “test");

prop.store(out, “–test–");

out.close();

2
.直接在jsp中操作,通过jsp内置对象获取可操作的绝对地址。

例:

// jsp页面


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

String realPath = path+"/WEB-INF/classes/abc.properties"
;

//java 程序


InputStream in = getClass().getClassLoader().getResourceAsStream("abc.properties"
);
// abc.properties放在webroot/WEB-INF/classes/目录下


prop.load(in);

in.close();

OutputStream out = new
FileOutputStream(path);
// path为通过页面传入的路径


prop.setProperty("abc"
, “abcccccc");

prop.store(out, “–test–");

out.close();

3
.只通过Java程序操作资源文件

InputStream in = new
FileInputStream(
"abc.properties"
);
// 相对路径,项目下的路径


OutputStream out = new
FileOutputStream(
"abc.properties"
);

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应用程序时一般所采取的策略。





 
 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


*Nov29,2006 10:34:34AM


*用来加载类,classpath下的资源文件,属性文件等。


*getExtendResource(StringrelativePath)方法,可以使用../符号来加载
classpath外部的资源。


*/


publicclass ClassLoaderUtil {

 
privatestatic Log log=LogFactory.getLog(ClassLoaderUtil.class
);

 /**


 
*Thread.currentThread().getContextClassLoader().getResource("")


 */




 /**


 
*加载Java类。 使用全限定类名


 
*@paramclassName


 
*@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的资源路径,返回文件的输入流


 *@paramrelativePath必须传递资源的相对路径。是相对于classpath的路径。如果需要查找
classpath外部的资源,需要使用 ../来查找


 *@return 文件输入流


 *@throwsIOException


 *@throwsMalformedURLException


 */


 
publicstatic InputStream getStream(String relativePath) throws
MalformedURLException, IOException {

 
 if
(!relativePath.contains(
"../"
)){

   return
getClassLoader().getResourceAsStream(relativePath);

 
 }else
{

 
  return
ClassLoaderUtil.getStreamByExtendResource(relativePath);

 
 }

 }

 /**


 
*


 *@paramurl


 *@return


 *@throwsIOException


 */


 
publicstatic InputStream getStream(URL url) throws
IOException{

 
 if
(url!=
null
){

 
  return
url.openStream();

 
 }else
{

 
  returnnull;

  }

 }

 /**


 
*


 
*@paramrelativePath必须传递资源的相对路径。是相对于classpath的路径。如果需要查找classpath外部的资源,需要使
用 ../来查找


 *@return


 *@throwsMalformedURLException


 *@throwsIOException


 */


 
publicstatic InputStream getStreamByExtendResource(String relativePath) throws
MalformedURLException, IOException{

 
 return
ClassLoaderUtil.getStream(ClassLoaderUtil.getExtendResource(relativePath));

 
}



 /**


 *提供相对于classpath的资源路径,返回属性对象,它是一个散列表


 *@paramresource


 *@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();

 
}

 /**


 *


 
*@paramrelativePath 必须传递资源的相对路径。是相对于classpath的路径。如果需要查找classpath外部的资源,需要
使 用../来查找


 *@return资
源的绝对URL


 
*@throwsMalformedURLException


 */


 
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;

 
}

 /**


 *


 
*@paramsource


 
*@paramdest


 
*@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;

 
}

 /**


 *


 
*@paramsource


 
*@paramdest


 
*@paramnum


 
*@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;

 
}

 /**


 *


 
*@paramresource


 
*@return


 */


 
publicstatic URL getResource(String resource){

 
 ClassLoaderUtil.log.info("传入的相对于classpath的路径:"
+resource) ;

 
 return
ClassLoaderUtil.getClassLoader().getResource(resource);

 
}

 /**


 *@paramargs


 *@throwsMalformedURLException


 */


 
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的绝对路径来拼资源的绝对路径!



1
.如何获得当前文件路径


用:

字符串类型:System.getProperty("user.dir"
);


合:

package
com.zcjl.test.base;

import
java.io.File;

public

class
Test {

public

static

void
main(String[] args)
throws
Exception {

System.out.println(

Thread.currentThread().getContextClassLoader().getResource(""
));

System.out.println(Test.class
.getClassLoader().getResource(
""
));

System.out.println(ClassLoader.getSystemResource(""
));

System.out.println(Test.class
.getResource(
""
));

System.out.println(Test.class
.getResource(
"/"
));



System.out.println(new
File(
""
).getAbsolutePath());

System.out.println(System.getProperty("user.dir"
));

}

}

file:/E:/workSpace/javaTest/target/classes/

file:/E:/workSpace/javaTest/target/classes/

file:/E:/workSpace/javaTest/target/classes/

file:/E:/workSpace/javaTest/target/classes/javaAPI/

file:/E:/workSpace/javaTest/target/classes/

E:/workSpace/javaTest

E:/workSpace/javaTest



2
.Web服务中

(1
).Weblogic

WebApplication
的系统文件根目录是你的weblogic安装所在根目录。

例如:如果你的weblogic安装在
c:/bea/weblogic700.....

那么,你的文件根路径就是c:/.


以,有两种方式能够让你访问你的服务器端的文件:

a.使用绝对路径:


如将你的参数文件放在c:/yourconfig/yourconf.properties,

直接使
用 new
FileInputStream(
"/yourconfig/yourconf.properties"
);

b.
使用相对路径:

相对路径的根目录就是你的webapplication的根路径,即WEB-INF的
上一级目录,将你的参数文件放在yourwebapp/yourconfig/yourconf.properties,


样使用:

new
FileInputStream(
"yourconfig/yourconf.properties"
);


两种方式均可,自己选择。

(2
).Tomcat


类中输出System.getProperty("user.dir"
);显示的
是%Tomcat_Home%/bin

(3
).Resin


是你的JSP放的相对路径,是JSP引擎执行这个JSP编译成SERVLET

的路径为根.比如用新建
文件法测试File f = new
File(
"a.htm"
);

这个
a.htm在resin的安装目录下

(4
).
如何读相对路径哪?

在Java文件中getResource或
getResourceAsStream均可

例:getClass().getResourceAsStream(filePath);//filePath可以是"/filename",这里的/代表web发布根路径下WEB-INF
/classes


也可以
getClass().getClassLoader().getResourceAsStream(filePath)//filePath不是带“/”的


(5
).获得文件真实路径

string file_real_path=request.getRealPath("mypath/filename"
);


常使用request.getRealPath("/"
);

4
.遗留问题

目前new
FileInputStream()只会使用绝对路径,相对



InputStream in1 = new
FileInputStream(
"abc1.properties"
);
// 相对路径


InputStream in2 = new
FileInputStream(
"/abc2.properties"
);
// 绝对路径,E盘下


InputStream in3 = new
FileInputStream(
"e://abc3.properties"
); //相对路径

5
.按Java文件类型分类读取配置文件

配 置
文件是应用系统中不可缺少的,可以增加程序的灵活性。java.util.Properties是从jdk1.2

有的类,一直到现在都支持load ()方法,jdk1.
4
以后
save(output,string) ->store(output,string)。如果只是单纯的读,根本不存在烦恼的问题。web层可以
通过 Thread.currentThread().getContextClassLoader().

getResourceAsStream("xx.properties"
) 获取;

Application
可以通过new
FileInputStream(
"xx.properties"
);直接在classes一级获取。关键是有时我们需要通过
web修改配置文件,我们不 能将路径写死了。经过测试觉得有以下心得:

1
.servlet中读写。如果运用Struts 或者Servlet可以直接在初始化参数中
配置,调用时根据servlet的getRealPath(
"/"
)
获取真实路径,再根据String file =
this
.servlet.getInitParameter(
"abc"
);获取相对的WEB-INF的相对路径。

例:

InputStream input = Thread.currentThread().getContextClassLoader().

getResourceAsStream("abc.properties"
);

Properties prop = new
Properties();

prop.load(input);

input.close();

OutputStream out = new
FileOutputStream(path);

prop.setProperty("abc"
, “test");

prop.store(out, “–test–");

out.close();

2
.直接在jsp中操作,通过jsp内置对象获取可操作的绝对地址。

例:

// jsp页面


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

String realPath = path+"/WEB-INF/classes/abc.properties"
;

//java 程序


InputStream in = getClass().getClassLoader().getResourceAsStream("abc.properties"
);
// abc.properties放在webroot/WEB-INF/classes/目录下


prop.load(in);

in.close();

OutputStream out = new
FileOutputStream(path);
// path为通过页面传入的路径


prop.setProperty("abc"
, “abcccccc");

prop.store(out, “–test–");

out.close();

3
.只通过Java程序操作资源文件

InputStream in = new
FileInputStream(
"abc.properties"
);
// 相对路径,项目下的路径


OutputStream out = new
FileOutputStream(
"abc.properties"
);

一、关于绝对路径和相对路径

1.基本概念的理解绝对路径:绝对路径就是你的主页上的文件或目录在硬盘上真正的路径,(URL和物理路径)例如:C:xyz
est.txt代表了test.txt文件的绝对路径。http://www.s.com/inx.htm也代表了一个URL绝对路径。相对路径:相对于
某个基准目录的路径。包含Web的相对路径(HTML中的相对目录),例如:在Servlet中,"/"代表Web应用的跟目录。和物理路径的相对表示。
例如:"./"
代表当前目录,"../"代表上级目录。这种类似的表示,也是属于相对路径。另外关于URI,URL,URN等内容,请参考RFC相关文档标准。RFC
2396: Uniform Resource Identifiers (URI): Generic
Syntax,(http://www.ietf.org/rfc/rfc2396.txt)2.关于JSP/Servlet中的相对路径和绝对路径。
2.1服务器端的地址服务器端的相对地址指的是相对于你的web应用的地址,这个地址是在服务器端解析的(不同于html和javascript中的相对
地址,他们是由客户端浏览器解析的)

1、request.getRealPath

方法:request.getRealPath("/")得到的路径:C:/Program Files/Apache Software
Foundation/Tomcat 5.5/webapps/strutsTest/

方法:request.getRealPath(".")得到的路径:C:/Program Files/Apache Software
Foundation/Tomcat 5.5/webapps/strutsTest/.

方法:request.getRealPath("")得到的路径:C:/Program Files/Apache Software
Foundation/Tomcat 5.5/webapps/strutsTest

request.getRealPath("web.xml")C:/Program Files/Apache Software
Foundation/Tomcat 5.5/webapps/strutsTest/web.xml

2、request.getParameter(""); ActionForm.getMyFile();

方法:String filepath =
request.getParameter("myFile");得到的路径:D:/VSS安装目录/users.txt

方法:String filepath =
ActionForm.getMyFile();得到的路径:D:/VSS安装目录/users.txt

--------------------------------------------------strutsTest 为工程名

myFile 在ActionForm中,为private String myFile;在jsp页面中:为<html:file
property="myFile"></html:file>

--------------------------------------------------

3、获得系统路径

在Application中: System.getProperty("user.dir")

在Servlet中: ServletContext servletContext =
config.getServletContext(); String rootPath =
servletContext.getRealPath("/");

在jsp中:application.getRealPath("")

4、其他1

1.可以在servlet的init方法里

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

这将获取web项目的全路径

例如 :E:/eclipseM9/workspace/tree/

tree是我web项目的根目录

2.你也可以随时在任意的class里调用

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

这将获取到classes目录的全路径

例如 : /D:/workspace/strutsTest/WebRoot/WEB-INF/classes/

还有 this.getClass().getResource("").getPath().toString();

这将获取 到 /D:/workspace/strutsTest/WebRoot/WEB-INF/classes/bl/

这个方法也可以不在web环境里确定路径,比较好用

3.request.getContextPath();

获得web根的上下文环境

如 /tree

tree是我的web项目的root context

5、其他2

java获取路径几种途径-

jdk如何判断程序中的路径呢?一般在编程中,文件路径分为相对路径和绝对路径,绝对路径是比较好处理的,但是不灵活,因此我们在编程中对文件进
行操作的时候,一般都是读取文件的相对路径,相对路径可能会复杂一点,但是也是比较简单的,相对的路径,主要是相对于谁,可以是类加载器的路径,或者是当
前 java文件下的路径,在jsp编程中可能是相对于站点的路径,相对于站点的路径,我们可以通过
getServletContext().getRealPath("/")
和request.getRealPath("/"):这个是取得站点的绝对路径; 而getContextPath():取得站点的虚拟路径;

2:class.getClassLoader.getPath():取得类加载器的路径:什么是类加载器呢?一般类加载器有系统的和用户自己定
义的;系统的ClassLoader就是jdk提供的,他的路径就是jdk下的路径,或者在jsp编程,比如Tomcat
,取得的类加载器的位置就是tomaca自己设计的加载器的路径,明白了这些之后,对于文件路径的操作就会相当的清楚,我们在编程的时候,只要想清楚我们
所操作的文件是相对于什么路径下的,取得相对路径就可以了.

6、总结

1、获取web服务器下的文件路径request.getRealPath("/")application.getRealPath("")
【jsp中 】ServletContext().getRealPath("")

System.getProperty("user.dir")【不同位置调用,获取的路径是动态变化的】

2、获取本地路径

jsp中,<html:file property="myFile"/>

request.getParameter("myFile");ActionForm.getMyFile();获取的值相同:如D:/VSS
安装目录/users.txt

*********************************

this.getClass().getClassLoader().getResource("").getPath();==/D:
/workspace/strutsTest/WebRoot/WEB-INF/classes
/this.getClass().getResource("").getPath().toString();==/D:/workspace
/strutsTest/WebRoot/WEB-INF/classes/bl/

3、获取相对路径

request.getContextPath();

如:/strutsTest
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: