Properties 文件是 Java 中常用的配置文件格式,用于存储简单的键值对,在 Java 中,我们通常使用 java.util.Properties 类来加载和读取这些文件。

核心问题:路径的来源
理解路径的来源是解决路径问题的关键,在 Java 应用中,Properties 文件的路径通常有以下几种情况:
- 相对于项目根目录的路径。
- 相对于当前工作目录的路径。
- 相对于
.class文件所在目录(类路径)的路径。 - 绝对路径。
使用类路径 是最推荐、最健壮的方式,因为它能确保你的应用程序在打包成 JAR 文件后依然能正常工作。
使用 ClassLoader 从类路径加载(最推荐)
这是处理 Properties 文件的标准和最佳实践,类路径包括你的项目 src 目录下的所有资源,以及所有依赖的 JAR 包。
对于 Maven/Gradle 项目
假设你的项目结构如下:

my-app/
├── pom.xml
└── src/
├── main/
│ ├── java/
│ │ └── com/
│ │ └── example/
│ │ └── Main.java
│ └── resources/
│ └── config.properties
└── test/
└── ...
config.properties 文件位于 src/main/resources 目录下,当项目被编译和打包时,resources 目录下的所有文件都会被原封不动地复制到最终输出的类路径的根目录下。
Java 代码示例:
Main.java
package com.example;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class Main {
public static void main(String[] args) {
// 1. 创建 Properties 对象
Properties props = new Properties();
// 2. 获取 ClassLoader
// 注意:使用 ClassLoader.getResourceAsStream() 时,路径不能以 '/' 开头
String fileName = "config.properties";
InputStream inputStream = Main.class.getClassLoader().getResourceAsStream(fileName);
// 3. 检查输入流是否为空(文件未找到)
if (inputStream == null) {
System.err.println("Sorry, unable to find " + fileName);
return;
}
try {
// 4. 加载属性文件
props.load(inputStream);
// 5. 获取属性值
String dbUrl = props.getProperty("database.url");
String dbUser = props.getProperty("database.username");
String dbPassword = props.getProperty("database.password");
System.out.println("Database URL: " + dbUrl);
System.out.println("Database User: " + dbUser);
System.out.println("Database Password: " + dbPassword);
} catch (IOException e) {
System.err.println("Error loading properties file: " + e.getMessage());
} finally {
// 6. 关闭输入流
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
config.properties 文件内容:

# Database Configuration database.url=jdbc:mysql://localhost:3306/mydb database.username=admin database.password=secret123
Properties 文件和 Java 类在同一个包下
假设项目结构如下:
my-app/
└── src/
└── main/
├── java/
│ └── com/
│ └── example/
│ ├── Main.java
│ └── config.properties <-- 文件和类在同一个包
└── resources/
在这种情况下,你可以使用 Class.getResourceAsStream(),路径需要以 开头,表示从当前类的包路径开始。
Java 代码示例:
// 在 com.example 包的 Main.java 类中
InputStream inputStream = Main.class.getResourceAsStream("/config.properties");
// 或者
// InputStream inputStream = Main.class.getResourceAsStream("config.properties"); // 两种写法都可以
使用 FileInputStream 从文件系统加载
这种方法直接使用操作系统的文件路径。不推荐在生产环境或需要打包成 JAR 的应用中使用,因为它依赖于文件系统的具体结构。
相对于项目根目录的路径
假设你的项目在 C:\projects\my-app,config.properties 在 C:\projects\my-app\config\ 目录下。
Java 代码示例:
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class Main {
public static void main(String[] args) {
Properties props = new Properties();
// 路径是相对于项目根目录的
// 注意:在 IDE (如 IntelliJ, Eclipse) 中,工作目录通常是项目根目录
String path = "config/config.properties"; // 使用正斜杠,跨平台兼容
try (FileInputStream fis = new FileInputStream(path)) {
props.load(fis);
System.out.println("Loaded properties from: " + path);
System.out.println(props.getProperty("database.url"));
} catch (IOException e) {
System.err.println("Error loading properties from file system: " + e.getMessage());
e.printStackTrace();
}
}
}
问题:
- 当你把项目打包成 JAR 文件后,
config/config.properties这个路径在 JAR 文件内部是不存在的,所以会加载失败。
使用绝对路径
这是最不灵活的方式,因为它将你的代码绑定到了一个特定的机器上。
String absolutePath = "C:/projects/my-app/config/config.properties";
// 或者
// String absolutePath = "C:\\projects\\my-app\\config\\config.properties"; // Windows风格
try (FileInputStream fis = new FileInputStream(absolutePath)) {
// ...
}
使用 Path 和 Files (Java 7+)
这是现代 Java 中处理文件 I/O 的推荐方式,它比 FileInputStream 更灵活,可以轻松结合类路径和文件系统。
从类路径加载
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.io.IOException;
import java.util.Properties;
public class Main {
public static void main(String[] args) {
// 获取类路径的根目录
// System.getProperty("java.class.path") 会返回类路径
// 这是一个更高级的用法,通常用于查找类路径下的文件
Path path = Paths.get("config.properties"); // 假设它在类路径根目录
if (Files.exists(path)) {
try {
Properties props = new Properties();
// Files.lines() 或 Files.newInputStream() 都可以
props.load(Files.newInputStream(path));
System.out.println(props.getProperty("database.url"));
} catch (IOException e) {
e.printStackTrace();
}
} else {
System.out.println("File not found at: " + path.toAbsolutePath());
}
}
}
注意: 这种方式是否能成功,取决于你的运行环境如何设置类路径,在 IDE 中运行通常没问题,但在命令行或 JAR 中可能需要确保文件在类路径中。
总结与最佳实践
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
ClassLoader.getResourceAsStream() |
跨平台,不依赖操作系统。 在打包成 JAR 后依然有效。 是 Java 应用的标准做法。 |
路径必须相对于类路径。 | 所有 Java 应用程序的首选,尤其是需要打包发布的应用。 |
Class.getResourceAsStream() |
同上,当文件与类在同一个包下时很方便。 | 同上,且路径规则需要特别注意(以 开头)。 | 当配置文件与使用它的 Java 类在同一个包下时。 |
FileInputStream |
直观,直接操作文件系统。 | 依赖文件系统结构,不灵活。 在 JAR 文件中无法工作。 |
快速原型开发、测试,或者配置文件明确位于项目外部且位置固定的情况。 |
Files.newInputStream() (Java 7+) |
现代 API,功能强大,可与其他 NIO 操作结合。 | 同 FileInputStream,依赖文件系统。 |
需要结合 NIO(如 Path, Files.walk() 等)进行复杂文件操作时。 |
最终建议
- 始终将
Properties文件放在src/main/resources目录下。 - 在代码中,总是使用
YourClass.class.getClassLoader().getResourceAsStream("your_file.properties")来加载它。 - 避免在代码中硬编码绝对路径或相对于项目根目录的路径,除非你有非常特殊且明确的需求。
这样做可以确保你的应用程序具有良好的可移植性和健壮性。
