前言
Java的路径问题,非常难搞。最近的工作涉及到创建和读取文件的工作,这里我就给大家彻底得解决Java路径问题。
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的相对路径。
1) ClassLoader类的getResource(String name) getResourceAsStream(String name)等方法,使用相对于当前项目的classpath的相对路径来查找资源。
2) 读取属性文件常用到的ResourceBundle类的getBundle(String path)也是如此
通过查看ClassLoader类及其相关类的源代码,我发现,它实际上还是使用了URI形式的绝对路径。
相对路径本质上还是绝对路径
因此,归根结底java本质上只能使用绝对路径来寻找资源。所有的相对路径寻找资源的方法,都不过是一些便利方法。不过是API在底层帮助我们构建了绝对路径,从而找到资源。
下面是一些得到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表示法。
public class PathUtil {
/***********************************************这些都是J2EE环境下的路径,不适合J2SE环境**************************************************************
* 1)obj.getClass().getClassLoader().getResource()>>>>>>>>>file:/E:/workspace/STY/Web/STY/WEB-INF/classes/(取到的classPath的路径)
* 2)obj.getClass().getClassLoader().getResource("/")>>>>>>>>null(是取不到路径的)
*
* 3)obj.getClass().getResource("")>>>>>>>>>file:/E:/workspace/STY/Web/STY/WEB-INF/classes/com/path/(取的是当前文件的文件夹路径,不包括该文件名)
* 4)obj.getClass().getResource("/")>>>>>>>>>file:/E:/workspace/STY/Web/STY/WEB-INF/classes/(取到的classPath的路径)
*
* 5)obj.getClass().getResource("1.xml")>>>>>>>>>file:/E:/workspace/STY/Web/STY/WEB-INF/classes/com/path/1.xml(可以使用相对路径)
* 6)obj.getClass().getClassLoader().getResource(com/path/1.xml"/")>>>>>>>>file:/E:/workspace/STY/Web/STY/WEB-INF/classes/com/path/1.xml(使用相对路径)
*
* 7)obj.getClass().getResource("/com/path/1.xml")>>>>>>>>file:/E:/workspace/STY/Web/STY/WEB-INF/classes/com/path/1.xml(使用相对路径)
*
* 总结:
* obj.getClass().getClassLoader().getResource()可以直接得到classpath,然后通过classpath进行相对地址取地址
* obj.getClass().getResource("/")也可以直接得到classpath,然后通过相对地址取地址
* obj.getClass().getResource("") 可以得到该类所存放的文件夹目录,然后通过相对地址取地址
***********************************************************************************************************************************************/
public static void main(String[] args) {
PathUtil obj = new PathUtil();
//1、obj.getClass().getClassLoader().getResource("")
String TestString = "obj.getClass().getClassLoader().getResource(" + ")";
System.out.println(TestString + ">>>>>>>>>" + obj.getClass().getClassLoader().getResource("com/../com/path/1.xml").getPath());
//2、obj.getClass().getClassLoader().getResource("/")
TestString = "obj.getClass().getClassLoader().getResource(" + "\"/\"" + ")";
System.out.println(TestString + ">>>>>>>>" + obj.getClass().getClassLoader().getResource("/"));
//3、obj.getClass().getResource("").getPath()
TestString = "obj.getClass().getResource("+"\"\")";
System.out.println(TestString + ">>>>>>>>>" + obj.getClass().getResource("").getPath());
//4、obj.getClass().getResource("/")
TestString ="obj.getClass().getResource(" + "\"/\"" +")";
System.out.println(TestString + ">>>>>>>>>" + obj.getClass().getResource("/").getPath());
//5、obj.getClass().getResource("1.xml")
TestString = "obj.getClass().getResource("+"\"1.xml\")";
System.out.println(TestString + ">>>>>>>>>" + obj.getClass().getResource("1.xml").getPath());
//6、obj.getClass().getClassLoader().getResource("com/path/1.xml")
TestString = "obj.getClass().getClassLoader().getResource(" + "com/path/1.xml\"/\"" + ")";
System.out.println(TestString + ">>>>>>>>" + obj.getClass().getClassLoader().getResource("com/path/1.xml").getPath());
//7、obj.getClass().getResource("/com/path/1.xml")
TestString = "obj.getClass().getResource(" + "\"/com/path/1.xml\"" +")";
System.out.println(TestString + ">>>>>>>>" + obj.getClass().getResource("/com/path/1.xml").getPath());
//8、获取文件的绝对地址(去掉路径前面的/)
String absolutePath= new File(obj.getClass().getResource("/com/path/1.xml").getPath()).getAbsolutePath();
System.out.println("absolutePath>>>>>>>>"+absolutePath);
String path = new File(obj.getClass().getResource("/com/path/1.xml").getPath()).getPath();
System.out.println("path>>>>>>>>"+path);
String pathIntetor = new File(absolutePath).getPath();
System.out.println("pathIntetor>>>>>>>>"+pathIntetor);
//9、取WEB-INF路径下的文件
String webInfPath = obj.getClass().getResource("/").getPath(); //得到classpath路径
webInfPath = webInfPath.substring(0, webInfPath.length()- "classes/".length())+"web.xml";
webInfPath = new File (webInfPath).getAbsolutePath();
System.out.println("webInfPath>>>>>>>>"+webInfPath);
//10、Thread类,得到的是claspath路径
String threadPath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
threadPath = new File(threadPath).getAbsolutePath();
System.out.println("threadPath>>>>>>>>"+threadPath);
//11、ClassLoader.getSystemResource("")
String classLoaderPath = ClassLoader.getSystemResource("").getPath();
//threadPath = new File(threadPath).getAbsolutePath();
System.out.println("classLoaderPath>>>>>>>>"+classLoaderPath);
}
}
终极path解决方案
public class ResourceLoaderUtil{
private static Log log = LogFactory.getLog(ResourceLoaderUtil.class);
//向上寻址分隔符
private final static String updest ="../";
//向下寻址分隔符
private final static String forwarddest= "/";
/**
* @Description:通过相对路径获取到制定的文件输入流
* @param relativePath
* @return
* @throws MalformedURLException
* @throws IOException
* @author wangweifeng
* @since:2014-10-24 下午04:23:55
*/
public static InputStream getStream(String relativePath) throws MalformedURLException, IOException {
return ResourceLoaderUtil.getStream(ResourceLoaderUtil.getExtendResource(relativePath));
}
/**
* @Description:根据提供的URL,返回文件的流
* @param url
* @return
* @throws IOException
* @author wangweifeng
* @since:2014-10-24 下午04:25:23
*/
public static InputStream getStream(URL url) throws IOException {
if (url != null) {
return url.openStream();
} else {
return null;
}
}
/**
* @Description:根据相对地址获取到Properties文件
* @param resource
* @return
* @author wangweifeng
* @since:2014-10-24 下午04:38:42
*/
public static Properties getProperties(String resource) {
Properties properties = new Properties();
try {
properties.load(getStream(resource));
} catch (IOException e) {
throw new RuntimeException("couldn‘t load properties file ‘" + resource + "‘", e);
}
return properties;
}
/**
* @Description:根据相对地址返回制定资源文件
* @param relativePath
* @return
* @author wangweifeng
* @since:2014-10-24 下午04:53:07
*/
public static File getFile(String relativePath) {
try {
File file = new File(ResourceLoaderUtil.getExtendResource(relativePath).getPath());
return file;
} catch (Exception e) {
throw new RuntimeException("couldn‘t load file ‘" + relativePath + "‘", e);
}
}
/**
* 思路:
* 1、当前路径,或者classpath内寻址
* 2、以"/"开始的寻址相对路径等于"",即从classpath路径开始
* 3、处理"/"之后的寻址的相对路径,不含有向上寻址的可能性,直接用clasLoader寻址
* 4、处理"/"之后的寻址的相对路径含有向上寻址符,则开始进行寻址逻辑
**/
public static URL getExtendResource(String relativePath) throws MalformedURLException {
ResourceLoaderUtil.log.info("传入的相对路径:" + relativePath);
URL resourceAbsoluteURL = null;
// 不以"../"(向上)或以"/"(向下)开头,即取的是claspath路径下的文件
if ((!relativePath.contains(updest)) && (!relativePath.startsWith(forwarddest))) { // 当前路基
resourceAbsoluteURL = ResourceLoaderUtil.getResource(relativePath);
System.out.println("相对寻址完成后路径为>>>>" + resourceAbsoluteURL);
return resourceAbsoluteURL;
}
if (relativePath.substring(0, 1).equals(forwarddest)) {
relativePath = relativePath.substring(1);
if ("".equals(relativePath) || !(relativePath.contains(updest))) {
return getExtendResource(relativePath);
}
}
// 从classpath向下寻址
String classPathAbsolutePath = ResourceLoaderUtil.getAbsolutePathOfClassLoaderClassPath();
// 有效寻址路径
String wildcardString = relativePath.substring(0, relativePath.lastIndexOf(updest) + updest.length());
relativePath = relativePath.substring(relativePath.lastIndexOf(updest) + updest.length());
classPathAbsolutePath = ResourceLoaderUtil.cutLastString(classPathAbsolutePath, wildcardString, updest);
String resourceAbsolutePath = classPathAbsolutePath + relativePath;
ResourceLoaderUtil.log.info("绝对路径:" + resourceAbsolutePath);
resourceAbsoluteURL = new URL(resourceAbsolutePath);
System.out.println("相对寻址完成后路径为>>>>" + resourceAbsoluteURL);
return resourceAbsoluteURL;
}
/**
* @Description:得到加载Java类,使用全限定类名。
* @param className
* @return
* @author wangweifeng
* @since:2014-10-24 下午01:15:39
*/
private static Class loadClass(String className) {
try {
return getClassLoader().loadClass(className);
} catch (ClassNotFoundException e) {
throw new RuntimeException("class not found ‘" + className + "‘", e);
}
}
/**
* @Description:得到类加载器
* @return
* @author wangweifeng
* @since:2014-10-24 下午01:14:39
*/
private static ClassLoader getClassLoader() {
return ResourceLoaderUtil.class.getClassLoader();
}
/**
*得到本Class所在的ClassLoader的Classpath的绝对路径。
*URL形式的
*@return
*/
private static String getAbsolutePathOfClassLoaderClassPath() {
ResourceLoaderUtil.log.info(ResourceLoaderUtil.getClassLoader().getResource("").toString());
return ResourceLoaderUtil.getClassLoader().getResource("").toString();
}
/**
* @Description:根据classLoader获取资源地址
* @param resource
* @return URL
* @author wangweifeng
* @since:2014-10-24 下午02:11:26
*/
private static URL getResource(String resource) {
ResourceLoaderUtil.log.info("传入的相对于classpath的路径:" + resource);
return ResourceLoaderUtil.getClassLoader().getResource(resource);
}
/**
* @descroption:相对寻址的核心方法
* @param 根据relativePath中包含向上寻址部分,获兑正确地址
* @param source == classPathAbsolutePath 相对地址
* @param relativePath 部分相对地址 ../lib/../../
* @param dest向上寻址分隔符,此处定义为../
* @author wangweifeng
* @since:2014-10-24 下午03:00:23
*/
private static String cutLastString(String source, String partRelativePath, String dest) {
if (partRelativePath.startsWith(dest)) {// 向上寻址一次
source = source.substring(0, source.lastIndexOf("/", source.length() - 2) + 1);
partRelativePath = partRelativePath.substring(dest.length());
System.out.println(source);
} else {
String forWordPath = partRelativePath.substring(0, partRelativePath.indexOf(dest));
partRelativePath = partRelativePath.substring(partRelativePath.indexOf(dest));
source = source + forWordPath;
System.out.println(source);
}
if (!"".equals(partRelativePath)) {
cutLastString(source, partRelativePath, dest);
}
return source;
}