首先一点很重要,Java中不存在标准的相对路径,各种相对路径取资源的方式都是基于某种规则转化为绝对路劲
然后一点也很重要,绝对不要直接使用绝对路径,否则死得很难看
基于以上两点,总结Resource路径问题无非归结为一点:找基点,也就是在某种环境下(web、j2ee或jar包等)通过合适的方式找到一个稳定的基点,然后通过这个基点找到你要的resource
Java中的基点有哪些呢?大致总结一下有以下几种:
1)classpath
如果你要找的资源在classpath下,那么通过classpath这个基点是比较合适的,而取得这个基点方式主要是通过ClassLoader来,具体方法就是 ClassLoader.getResource(String name),而取得ClassLoader的方式很多,比如:
- Thread.currentThread().getContextClassLoader()
- clazz.getClassLoader()
- ClassLoader. getSystemClassLoader()
ClassLoader找resource的实现原理就是先递归在parent classLoader中从所在classpath里加载resource(最终如何加载JDK未开源),如果所有层级的classLoader都未找到,则调用findResource方法来找,而这个方法是暴露给自制classLoader来现实的,因此给了在classpath之外加载resource的机会。
class.getResource(String res)的使用
该方法是根据类的相对路径来访问资源的。如果该类没有package,则类的根路径是就是当前路径;如果该类有package,则类的根路径是定级包所在的路径。例如: Drawing没有定义package,Drawing.class与images在相同路径下这样访问:当前路径就是根路径 Image img = (new ImageIcon(Drawing.class.getResource("images/title.gif"))).getImage(); 什么都不加当前路径 Image img = (new ImageIcon(Drawing.class.getResource("./images/title.gif"))).getImage(); ./当前目录 Image img = (new ImageIcon(Drawing.class.getResource("/images/title.gif"))).getImage(); /根目录 Drawing定义package myjava.gui,Drawing.class位于myjava/gui目录,myjava与images在相同路径下这样访问: Image img = (new ImageIcon(Drawing.class.getResource("/images/title.gif"))).getImage();(实际中建议使用该方式) Image img = (new ImageIcon(Drawing.class.getResource("../../images/title.gif"))).getImage(); ../上一级目录 =================================== Class.getResource()方法实际上委托装入该类的类装载器,返回一个用于读取类文件资源的URL;或者,当指定的类名字不能在当前的classpath中找到时,Class.getResource()方法返回null。 =================================== 可以看到,Class的getResource方法,实际上是靠调入这个类的ClassLoader的getResource方法来实现的,如果调入这个类的ClassLoader是原生的BootStrap ClassLoader,这个ClassLoader是用C++写成的,在Java中没有相对应的物件。这时候的实现靠的是ClassLoader的静态方法getSystemResource。 只有当使用Class类的getResource方法的时候,才会有下面介绍的那种算法。 这种算法就是说,如果你指定的路径以/开头,那么就是从ClassPath的起点开始寻找这个路径。如果直接以某个名字开头,那么就是从当前包名的目录为起点开始寻找。 所以大家如果用过hibernate就知道,有些表示类到数据库表的映射关系的xml文件就和这个类的class文件放在一起,这样它就直接使用这个类.class.getResource方法来得到这个xml文件。而在使用ClassLoader的getResource方法的时候,永远是以Classpath为直接起点开始寻找资源的。不用担心从什么包开始寻找的问题。用Class.getResource不加/就是从当前包开始找,用ClassLoader.getResource不加/就是直接从Classpath的起点开始寻找。当然,如果你觉得有困难,你定位资源的时候全部都使用/开头的方式就好了 |
2) 当前用户目录
就是相对于System.getProperty("user.dir" )返回的路径, 对于一般项目,这是项目的根路径。对于JavaEE服务器,这可能是服务器的某个路径。这个并没有统一的规范! 然而, 默认情况下,java.io 包中的类总是根据当前用户目录来分析相对路径名,如new File("xxx"),就是在 System.getProperty("user.dir" )路径下找xxx文件。因此,通过这种方式来定位文件可能会出现移植问题。
java.version | Java 运行时环境版本 |
java.vendor | Java 运行时环境供应商 |
java.vendor.url | Java 供应商的 URL |
java.home | Java 安装目录 |
java.vm.specification.version | Java 虚拟机规范版本 |
java.vm.specification.vendor | Java 虚拟机规范供应商 |
java.vm.specification.name | Java 虚拟机规范名称 |
java.vm.version | Java 虚拟机实现版本 |
java.vm.vendor | Java 虚拟机实现供应商 |
java.vm.name | Java 虚拟机实现名称 |
java.specification.version | Java 运行时环境规范版本 |
java.specification.vendor | Java 运行时环境规范供应商 |
java.specification.name | Java 运行时环境规范名称 |
java.class.version | Java 类格式版本号 |
java.class.path | Java 类路径 |
java.library.path | 加载库时搜索的路径列表 |
java.io.tmpdir | 默认的临时文件路径 |
java.compiler | 要使用的 JIT 编译器的名称 |
java.ext.dirs | 一个或多个扩展目录的路径 |
os.name | 操作系统的名称 |
os.arch | 操作系统的架构 |
os.version | 操作系统的版本 |
file.separator | 文件分隔符(在 UNIX 系统中是“/”) |
path.separator | 路径分隔符(在 UNIX 系统中是“:”) |
line.separator | 行分隔符(在 UNIX 系统中是“/n”) |
user.name | 用户的账户名称 |
user.home | 用户的主目录 |
user.dir | 用户的当前工作目录 |
获取的代码示例:
package bean;
public class SystemProperty
{
public static void main(String args[])
{
System.out.println("java_vendor:" + System.getProperty("java.vendor"));
System.out.println("java_vendor_url:" + System.getProperty("java.vendor.url"));
System.out.println("java_home:" + System.getProperty("java.home"));
System.out.println("java_class_version:" + System.getProperty("java.class.version"));
System.out.println("java_class_path:" + System.getProperty("java.class.path"));
System.out.println("java.library.path:" + System.getProperty("java.library.path"));
System.out.println("os_name:" + System.getProperty("os.name"));
System.out.println("os_arch:" + System.getProperty("os.arch"));
System.out.println("os_version:" + System.getProperty("os.version"));
System.out.println("user_name:" + System.getProperty("user.name"));
System.out.println("user_home:" + System.getProperty("user.home"));
System.out.println("user_dir:" + System.getProperty("user.dir"));
System.out.println("java_vm_specification_version:" + System.getProperty("java.vm.specification.version"));
System.out.println("java_vm_specification_vendor:" + System.getProperty("java.vm.specification.vendor"));
System.out.println("java_vm_specification_name:" + System.getProperty("java.vm.specification.name"));
System.out.println("java_vm_version:" + System.getProperty("java.vm.version"));
System.out.println("java_vm_vendor:" + System.getProperty("java.vm.vendor"));
System.out.println("java_vm_name:" + System.getProperty("java.vm.name"));
System.out.println("java_ext_dirs:" + System.getProperty("java.ext.dirs"));
System.out.println("file_separator:" + System.getProperty("file.separator"));
System.out.println("path_separator:" + System.getProperty("path.separator"));
System.out.println("line_separator:" + System.getProperty("line.separator"));
}
}
输出:
java_vendor:Oracle Corporation
java_vendor_url:http://java.oracle.com/
java_home:C:\Program Files\Java\jdk1.7.0_11\jre
java_class_version:51.0
java_class_path:D:\workspace\Bean Example\bin;D:\workspace\mgscore\bin;D:\workspace\mgslib\libs\third.jar;D:\workspace\mgslib\bin;D:\workspace\mgslib\qqlibs\java-udp-2.0.jar;D:\workspace\mgslib\qqlibs\commons-codec-1.4.jar;D:\workspace\mgslib\qqlibs\commons-httpclient-3.0.jar;D:\workspace\mgslib\qqlibs\commons-logging-1.1.1.jar;D:\workspace\mmoGame\bin;D:\Program Files (x86)\eclipse-standard-kepler\plugins\org.aspectj.runtime_1.7.3.20130613144500-a.jar;D:\workspace\JavaUdp2.0\bin;D:\workspace\JavaUdp2.0\lib\commons-lang3-3.1.jar
java.library.path:C:\Program Files\Java\jdk1.7.0_11\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:/Program Files/Java/jdk1.7.0_11/bin/../jre/bin/server;C:/Program Files/Java/jdk1.7.0_11/bin/../jre/bin;C:/Program Files/Java/jdk1.7.0_11/bin/../jre/lib/amd64;C:\Program Files\Java\jdk1.7.0_11\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\Java\jdk1.7.0_11\jre\bin;C:\Program Files\TortoiseSVN\bin;C:\Program Files (x86)\ICBCEbankTools\Gemplus\GemSafe Libraries\BIN\;E:\Baidu\BaiduPan\java\开发工具\apache-maven-3.0.5\bin;D:\Program Files (x86)\eclipse-standard-kepler;;.
os_name:Windows 7
os_arch:amd64
os_version:6.1
user_name:SoulGame
user_home:C:\Users\SoulGame
user_dir:D:\workspace\Bean Example
java_vm_specification_version:1.7
java_vm_specification_vendor:Oracle Corporation
java_vm_specification_name:Java Virtual Machine Specification
java_vm_version:23.6-b04
java_vm_vendor:Oracle Corporation
java_vm_name:Java HotSpot(TM) 64-Bit Server VM
java_ext_dirs:C:\Program Files\Java\jdk1.7.0_11\jre\lib\ext;C:\Windows\Sun\Java\lib\ext
file_separator:\
path_separator:;
line_separator:
3) Web应用程序的根目录
在Web应用程序中,我们一般通过ServletContext.getRealPath("/" )方法得到Web应用程序的根目录的绝对路径。
掌握了上面几个基点,就能很轻松得定位你要找的resource,只不过要清晰地认识到不要只图一时快活,而不管将来移植的死活,要确保能任何环境下(j2se or web,windows or linux)不出问题。