Java 读取文件时的路径问题

0. 文章摘要

Class 和 ClassLoader 各有一个获取文件路径的方法,以及一个将文件转换为 InputStream 的方法,用法略有不同。本文对这个四个方法的使用进行说明,并提供示例代码;并在文末提供了 FileInputStream 的使用案例。

1. 方法说明

  • Class

    1. getResource(String pathToFile)
    2. getResourceAsStream(String pathToFile)
      当参数是一个相对路径时,被看作是从调用该方法的 Class 实例所属的类开始的;当参数是一个绝对路径时,被看作是从 classpath 开始的。
  • ClassLoader

    1. getResource(String pathToFile)
    2. 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 ,ClassClassLoader 没有可以操作它的方法,但可以将它相对于项目根目录的路径作为 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值