仅供参考,如有错误或不足欢迎留言指正。
我们以maven的web项目为例:
接下来我们看看工程结构:这里只讨论src目录和target目录
src目录:
- src/main/java: java:起初生成maven项目时并没有这个resource文件夹,是建立maven项目后手动添加进去的,用于存放java源文件
- src/main/resources:存放项目的各种资源(如图片文本之类的)及全局配置文件
- src/main/webapp:webapp目录是web目录所特有的目录,不作详细介绍
target目录:
- classes:这个就是classpath目录,即存放java字节码文件以及相关配置文件(如properties文件)的根目录,后面会用代码演示资源文件的路径及相关知识
target目录下的其他目录不再做介绍,与本文讨论的知识并无多大关系。
src 与 target: src/main/下的java文件下的.java文件编译后的.class文件及resources文件相关资源文件都会在target/classes中。
关于java的字节码文件存放位置: target/classes目录下会生成对应的相关字节码文件及相关的包文件夹
关于src/main/resources文件:这是一个专门存放各类信息文件的配置文件夹,笔者曾犯的一个错误就是将配置文件放在了java目录下,导致始终无法获取配置文件的输入流
说完了相关文件介绍,我们进入正题:
首先介绍两个方法:getResource(String filePath)
和getResourceAsStream(String filePath)
getResource(String filePath):下面上代码:
分析:通过运行结果我们可以看到通过Class类对象调用getResource(String filePath)方法获取的路径是classes文件下的类路径但不包含类本身;而通过ClassLoader类调用的getResource(String filePath)方法,则输出到classpath的根目录。
ok,说到此处,我觉得有上 API文档的必要了。我们来看看Class和ClassLoader类的getResource(),getResourceAsStream()方法:
Class类的getResource()和getResourceAsStream():
getResource()方法注释:
<li> If the {@code name} begins with a {@code '/'}
* (<tt>'\u002f'</tt>), then the absolute name of the resource is the
* portion of the {@code name} following the {@code '/'}
* <li> Otherwise, the absolute name is of the following form:
* <blockquote>
* {@code modified_package_name/name}
* </blockquote>
* <p> Where the {@code modified_package_name} is the package name of this object with {@code '/'} substituted for {@code '.'}
* (<tt>'\u002e'</tt>).
大致意思是:如果路径名(也就是filePath)以 “/” 开头,那么资源的绝对路径名是文件路径的一部分。否则,其路径名为 “包名/文件名”,最后还特别说明了一下:包名的点被 “/”所替代掉。
getResourceAsStream()注释的资源路径说明与getResource()方法相同,可以自己区查阅API文档。
ClassLoader类的getResource()和getResourceAsStream():
getResource()注释:
* Finds the resource with the given name. A resource is some data(images, audio, text, etc) that can be accessed by class code in a way that is independent of the location of the code.
* <p> The name of a resource is a '<tt>/</tt>'-separated path name that
* identifies the resource.
* <p> This method will first search the parent class loader for the
* resource; if the parent is <tt>null</tt> the path of the class loader
* built-in to the virtual machine is searched. That failing, this method
* will invoke {@link #findResource(String)} to find the resource. </p>
大致意思是:通过给定的名字搜索资源。这些资源指的是那些可以通过一种不依赖java代码的方式而被java文件所接收的资源(例如:图片,音频,文本等等)。关于搜索规则,其中提到了一个关键点:首先搜索父目录(字节码目录classes)。通过这点,我们已经可以知道该方法的filepath开头是不加”/”的,即从classes目录开始搜索。而关于getResourceAsStream()的搜索规则,文档注释中说与getResource()一样,在此就不再贴注释了。
说的再多,不如贴代码来的直接:
首先在如图mysql.properties文件位置:
同时呢,我们可以在classes下看到相关的文件夹config及mysql.properties文件:
前面我们提到过,资源的路径取的是classpath(即类加载路径)下的路径。接下来我们要讨论的是分别通过Class及ClassLoader类的getResourceAsStream()方法获取mysql.properites文件流从而获取数据。
public class Test {
public static void main(String[] args) throws Exception {
getStreamByClass("/config/mysql.properties");
getStreamByClassLoader("config/mysql.properties");
}
public static void getStreamByClass(String filePath) throws Exception {
//通过Class的getResourceAsStream()获取properties文件输入流
InputStream in = Test.class.getResourceAsStream(filePath);
//当然,也可以通过实例获取Class对象
InputStream in1 = new Test().getClass().getResourceAsStream(filePath);
printProperties(in);
printProperties(in1);
}
public static void getStreamByClassLoader(String filePath) throws Exception {
//通过ClassLoader的getResourceAsStream()获取输入流
InputStream in = Test.class.getClassLoader().getResourceAsStream(filePath);
//同样的,通过实例也可以获取ClassLoader对象
InputStream in1 = new Test().getClass().getClassLoader().getResourceAsStream(filePath);
printProperties(in);
printProperties(in1);
}
public static void printProperties(InputStream in) throws Exception {
Properties pro = new Properties();
pro.load(in);
System.out.println("url: " + pro.getProperty("url")
+ "user: " + pro.getProperty("user")
+ "password: " + pro.getProperty("password"));
}
}
运行结果如下: