文章目录
0. 文章摘要
Class 和 ClassLoader 各有一个获取文件路径的方法,以及一个将文件转换为 InputStream 的方法,用法略有不同。本文对这个四个方法的使用进行说明,并提供示例代码;并在文末提供了 FileInputStream 的使用案例。
1. 方法说明
-
Class
getResource(String pathToFile)
getResourceAsStream(String pathToFile)
当参数是一个相对路径时,被看作是从调用该方法的 Class 实例所属的类开始的;当参数是一个绝对路径时,被看作是从 classpath 开始的。
-
ClassLoader
getResource(String pathToFile)
getResourceAsStream(String pathToFile)
总是将参数看作从 classpath 开始的绝对路径,所以不必加前导/
,加了反而不对。
上述说明即为本文精华,如果没看懂,可以思考如下代码片段:
以下 3 个 URL 是相同的
URL url1 = foo.bar.Baz.class.getResource("xyz.txt");
URL url1 = foo.bar.Baz.class.getResource("/foo/bar/xyz.txt");
URL url2 = foo.bar.Baz.class.getClassLoader().getResource("foo/bar/xyz.txt");
以下 3 个 InputStream 的也是相同的
InputStream in = foo.bar.Baz.class.getResourceAsStream("xyz.txt");
InputStream in = foo.bar.Baz.class.getResourceAsStream("/foo/bar/xyz.txt");
InputStream in = foo.bar.Baz.class.getClassLoader().getResourceAsStream("foo/bar/xyz.txt");
如果仍需要查看更具体的例子,请考察下面的示例程序。
2. 程序示例
2.1 程序说明
以下程序尝试获取 db1.properties 及 db2.properties 这两个文件的路径,以及将它们转换成 InputStream。
至于项目根目录下的文件 xanadu.txt ,Class
和 ClassLoader
没有可以操作它的方法,但可以将它相对于项目根目录的路径作为 FileInputStream 的参数创建一个文件流。
2.2 目录结构(Maven 项目)
D:/learn-java/
├── pom.xml
├── src
│ └── main
│ ├── java
│ │ └── com
│ │ └── feng
│ │ └── learnjava
│ │ ├── App.java
│ │ └── db1.properties ?
│ └── resources
│ └── db2.properties ?
├── target
│ └── classes
│ ├── com
│ │ └── feng
│ │ └── learnjava
│ │ ├── App.class
│ │ └── db1.properties ?
│ └── db2.properties ?
└── xanadu.txt ?
2.3 工程视图
2.4 Java 代码
2.4.1 Class.getResourece 与 ClassLoader.getResourece
// 1. 参数为空字符串
String path1 = this.getClass().getResource("").getPath();
// /D:/learn-java/target/classes/com/feng/
String path1_1 = this.getClass().getResource("/").getPath();
// /D:/learn-java/target/classes/
String path2 = this.getClass().getClassLoader().getResource("").getPath();
// /D:/learn-java/target/classes/
// 2. 使用 Class.getResource 获取 db1.properties 的路径
String path3 = this.getClass().getResource("db1.properties").getPath();
String path4 = this.getClass().getResource("/com/feng/db1.properties").getPath();
// 3. 使用 Class.getResource 获取 db2.properties 的路径
String path5 = this.getClass().getResource("../../db2.properties").getPath();
String path6 = this.getClass().getResource("/db2.properties").getPath();
// 4. 使用 ClassLoader.getResource 获取 db1.properties 的路径
String path7 = this.getClass().getClassLoader().getResource("com/feng/db1.properties").getPath();
// 5. 使用 ClassLoader.getResource 获取 db2.properties 的路径
String path8 = this.getClass().getClassLoader().getResource("db2.properties").getPath();
2.4.2 Class.getResourceAsStream 与 ClassLoader.getResourceAsStream
路径规则与 getResource 方法是相同的。
InputStream in1 = null;
InputStream in2 = null;
InputStream in3 = null;
InputStream in4 = null;
try{
in1 = this.getClass().getResourceAsStream("db1.properties");
in2 = this.getClass().getResourceAsStream("../../db2.properties");
in3 = this.getClass().getClassLoader().getResourceAsStream("com/feng/db1.properties");
in4 = this.getClass().getClassLoader().getResourceAsStream("db2.properties");
} finally {
if(in1 != null) in1.close();
if(in2 != null) in2.close();
if(in3 != null) in3.close();
if(in4 != null) in4.close();
}
2.4.3 FileInputStream(String path/to/file)
参数被看作是从项目根目录开始的路径。
需要注意的是,项目根目录下的文件,不会被 Maven 打包到 jar 包或 war 包中,所以不要把配置或属性文件放在项目根目录,而应该放在 src/main/resources
下。
FileInputStream in1 = null;
FileInputStream in2 = null;
FileInputStream in3 = null;
FileOutputStream out = null;
try {
in1 = new FileInputStream("xanadu.txt");
String path1 = this.getClass().getResource("db1.properties").getPath();
in2 = new FileInputStream(path1);
String path2 = this.getClass().getResource("/db2.properties").getPath();
in3 = new FileInputStream(path2);
String path3 = this.getClass().getResource("/").getPath() + "copy.properties";
out = new FileOutputStream(path3);
int c = 0;
while((c = in3.read()) != -1){
out.write(c);
}
} finally {
if (in1 != null) in1.close();
if (in2 != null) in2.close();
if (in3 != null) in3.close();
if (out != null) out.close();
}
EOF