当我们用idea创建maven项目的时候,项目文件的结构如下图所示:
其中项目主要源代码一般放置在src/main/java文件夹下
这里将后续要用到的所有外部资源文件都放在src/main/resources文件夹下,推荐读者采用这种方式来管理文件,便于后续的讲解和文件管理。注意:对于src/main/resources文件夹下的所有文件,idea在编译后都会在src/target/classes文件夹下保留其拷贝,因此在这两个文件夹下的同名同类型文件的内容是一模一样的。
当要调用resources文件夹中的资源文件时,我们肯定想尽可能避免用到绝对路径读取文件,因为这样程序移植或者在其他设备上运行时又要重新修改绝对路径,所以可以通过getResourceAsStream()方法,使用相对路径方式读取到文件,这样在程序移植或者更换设备运行时,只需要保证将所有要调用的资源文件都放置在src/main/resources文件夹下,而不需要再修改程序本身,该方法有两种形式:
this.getClass().getResourceAsStream()
this.getClass().getClassLoader().getResourceAsStream()
以下面的项目为例,这里演示的加载1.txt文件,文件内容是Hello,world
package com.first;
import org.apache.commons.io.IOUtils;
import java.io.InputStream;
public class BJava {
public static void main(String[] args) throws Exception {
InputStream is = this.getClass().getResourceAsStream("/1.txt");
String s = IOUtils.toString(is);
System.out.println(s);
}
}
结果:
this.getClass().getResourceAsStream("/1.txt" )从src/target/classes文件夹下读取文件,由上面项目结构图可知文件存在,所以程序可以拿到资源,不报错。若将方法中的/去掉,则读取的是当前类所在文件夹下的文件,不存在该文件,显然报空指针异常。
package com.first;
import org.apache.commons.io.IOUtils;
import java.io.InputStream;
public class BJava {
public static void main(String[] args) throws Exception {
InputStream is = this.getClass().getResourceAsStream("1.txt");
String s = IOUtils.toString(is);
System.out.println(s);
}
}
结果:
this.getClass().getResourceAsStream(“1.txt")是从当前程序对应类所在的文件夹,即在src/main/java/com/first文件夹中找1.txt,该文件夹下没有1.txt,所以程序找不着,会报空指针异常。
InputStream is = this.getClass().getClassLoader().getResourceAsStream(fileName)
package com.first;
import org.apache.commons.io.IOUtils;
import java.io.InputStream;
public class BJava {
public static void main(String[] args) throws Exception {
InputStream is = this.getClass().getClassLoader().getResourceAsStream("1.txt");
String s = IOUtils.toString(is);
System.out.println(s);
}
}
结果:
this.getClass().getClassLoader().getResourceAsStream("1.txt")直接从src/target/classes文件夹下读取文件,存在该文件,所以程序不报错
(1)InputStream is = this.getClass().getResourceAsStream(fileName)
会从当前类所在的文件夹下去找,这个文件如果不和该类在一个目录下,就找不到
(2)InputStream is = this.getClass().getResourceAsStream("/" + fileName)
会从编译后的整个src/target/classes目录下去找,maven也会把资源文件打包进classes文件夹,如果该文件存在,则可以找到
(3)InputStream is = this.getClass().getClassLoader().getResourceAsStream(fileName)
会从编译后的整个src/target/classes目录下去找,文件名前不需要再加/符号,也就是说在(2)中的文件名fileName前加一个/就可以实现和(3)一样的功能
因此,当使用读取文件时,若程序报空指针异常,则笔者建议将文件全部放在src/main/resources文件夹后,再用上面(2)和(3)两种方式读取文件