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
题。
我编写了一个方法,比
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
相关文章推荐
- java文件路径操作详细(转载)
- java文件路径操作详细
- java文件路径操作详细
- java文件路径操作详细
- java文件路径操作详细
- java文件操作 之 创建文件夹路径和新文件
- java文件路径操作
- iOS清除缓存详细解析、app文件路径操作,真机沙盒理解
- java获取文件夹内文件数和文件详细路径
- javabean操作文件正确,但是Jsp调用javabean时文件路径出错问题解决之JavaBean访问本地文件实现路径无关实现方法
- Java中各种文件类型操作的代码与详细文件IO讲解
- JAVA操作properties文件【要注意properties文件的路径】
- [置顶] Java文件操作之类详细讲解
- java文件操作之路径的获得
- Java中的文件与磁盘操作技术详细解析
- java文件路径操作
- iOS清除缓存详细解析、app文件路径操作,自己个人对于沙盒的理解
- HDFS java操作(二)FileStatus 获取文件属性,globStatus 进行路径过滤
- java操作Properties属性文件及获取项目部署服务器路径
- Java——文件路径操作