什么是 Properties 文件?
我们来看一个典型的 config.properties 文件示例:

# Database Configuration db.driver=com.mysql.cj.jdbc.Driver db.url=jdbc:mysql://localhost:3306/mydb db.username=root db.password=secret # Application Settings app.name=My Awesome App app.version=1.0.0
文件中的 开头的是注释,键和值用 或 分隔。
核心加载方法
Java 提供了多种加载 Properties 文件的方式,适用于不同的场景(从类路径加载、从文件系统加载、从网络加载等)。
使用 ClassLoader.getResourceAsStream() (推荐用于类路径资源)
这是最常见、最推荐的方法,尤其适用于在 Maven 或 Gradle 项目中,将配置文件放在 src/main/resources 目录下的情况。
工作原理: 这种方式将 Properties 文件视为类路径(Classpath)中的一个资源,由类加载器负责加载,这使得应用程序打包成 JAR 文件后,配置文件依然可以正常读取。

代码示例:
import java.io.InputStream;
import java.util.Properties;
public class PropertiesLoaderWithClassLoader {
public static void main(String[] args) {
// 1. 创建 Properties 对象
Properties props = new Properties();
// 2. 使用 try-with-resources 确保 InputStream 自动关闭
try (InputStream input = PropertiesLoaderWithClassLoader.class.getClassLoader().getResourceAsStream("config.properties")) {
// 3. 检查输入流是否为空
if (input == null) {
System.out.println("Sorry, unable to find config.properties");
return;
}
// 4. 加载 Properties 文件
props.load(input);
// 5. 读取并打印属性
System.out.println("Database URL: " + props.getProperty("db.url"));
System.out.println("Username: " + props.getProperty("db.username"));
System.out.println("App Name: " + props.getProperty("app.name"));
System.out.println("App Version: " + props.getProperty("app.version"));
// 如果属性不存在,可以提供默认值
System.out.println("Debug Mode: " + props.getProperty("debug.mode", "false"));
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
关键点:
getClassLoader().getResourceAsStream("config.properties"):config.properties的路径是相对于类路径的根目录的。- 文件位置: 如果你的项目是 Maven 项目,需要将
config.properties放在src/main/resources目录下。 - 路径问题: 路径中不要以 开头,否则会从类路径的根开始查找,如果要以 开头,应该使用
Class.getResourceAsStream()。
使用 Class.getResourceAsStream()
与方法一类似,但路径的解析方式略有不同。
工作原理: 如果路径以 开头,则从类路径的根目录查找,如果路径不以 开头,则从当前类的包路径下查找。
代码示例:
假设你的类是 com.example.PropertiesLoader,config.properties 在 src/main/resources/com/example/ 目录下。
import java.io.InputStream;
import java.util.Properties;
public class PropertiesLoaderWithClass {
public static void main(String[] args) {
Properties props = new Properties();
// 假设 config.properties 和这个类在同一个包下
// 路径不以 '/' 开头,从当前类的包下查找
try (InputStream input = PropertiesLoaderWithClass.class.getResourceAsStream("config.properties")) {
if (input == null) {
System.out.println("Sorry, unable to find config.properties in the same package.");
return;
}
props.load(input);
System.out.println("App Name: " + props.getProperty("app.name"));
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
关键点:
- 路径前缀: 路径前是否有 决定了查找的起点。
- 灵活性: 当配置文件和类在同一个包下时,这种方式很方便。
使用 FileInputStream (用于从文件系统加载)
如果你的配置文件在项目之外的某个固定位置,或者你想通过绝对路径/相对路径来加载,这种方法非常直接。
代码示例:
假设 config.properties 文件位于项目根目录下的 config 文件夹中。
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class PropertiesLoaderWithFileInputStream {
public static void main(String[] args) {
Properties props = new Properties();
// 使用绝对路径
// String filePath = "C:/path/to/your/config/config.properties";
// 使用相对路径 (相对于项目根目录)
String filePath = "config/config.properties";
try (FileInputStream input = new FileInputStream(filePath)) {
props.load(input);
System.out.println("Database URL: " + props.getProperty("db.url"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
关键点:
- 路径灵活性: 可以是绝对路径或相对于当前工作目录(通常是项目根目录)的相对路径。
- 依赖文件系统: 应用程序部署后,必须确保该文件存在于指定路径,否则会抛出
FileNotFoundException,这使得应用程序的可移植性变差。
使用 java.util.ResourceBundle (国际化专用)
ResourceBundle 主要用于国际化(i18n),但它也可以用来加载 Properties 文件,它不返回 Properties 对象,而是允许你按需获取键对应的值。
工作原理: ResourceBundle 会根据默认的 Locale(或指定的 Locale)查找匹配的文件,文件命名规则是 basename_<locale>.properties,messages_en_US.properties,如果没有特定地区的文件,则加载 messages.properties。
代码示例:
假设 config.properties 文件在 src/main/resources 目录下。
import java.util.ResourceBundle;
public class PropertiesLoaderWithResourceBundle {
public static void main(String[] args) {
// 1. 基础名称,不包含 .properties 后缀
// ResourceBundle 会自动从类路径中查找
String baseName = "config";
// 2. 获取 ResourceBundle 对象
// 会自动加载 config.properties 或 config_<locale>.properties
ResourceBundle rb = ResourceBundle.getBundle(baseName);
// 3. 获取值
// 如果键不存在,会抛出 MissingResourceException
System.out.println("App Name: " + rb.getString("app.name"));
System.out.println("Username: " + rb.getString("db.username"));
// 获取带默认值的值(需要自己实现,ResourceBundle本身不直接支持)
String debugMode = rb.containsKey("debug.mode") ? rb.getString("debug.mode") : "false";
System.out.println("Debug Mode: " + debugMode);
}
}
关键点:
- 国际化: 这是它的主要设计用途。
- 性能:
ResourceBundle会被缓存,多次调用getBundle获取相同的baseName会返回同一个实例,性能较好。 - 限制: 主要用于读取,不能像
Properties对象那样进行修改或重新加载。
总结与最佳实践
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
ClassLoader.getResourceAsStream() |
推荐,配置文件在类路径中(如 src/main/resources)。 |
与项目结构解耦,可移植性好(JAR 内资源),是标准做法。 | 路径是相对于类路径的,对新手可能有点抽象。 |
Class.getResourceAsStream() |
配置文件与类在同一个包下。 | 路径解析直观(基于类所在包)。 | 灵活性不如 ClassLoader 的方法。 |
FileInputStream |
配置文件在项目外的固定位置。 | 路径非常灵活,绝对/相对路径均可。 | 可移植性差,依赖文件系统,部署时易出错。 |
ResourceBundle |
国际化/多语言场景。 | 性能好(缓存),专为 i18n 设计。 | 不适合动态修改配置,主要用于读取。 |
最佳实践建议:
- 首选
ClassLoader.getResourceAsStream():对于绝大多数 Java 项目,尤其是使用构建工具(Maven/Gradle)的项目,这是最标准、最可靠的方式,将配置文件放在src/main/resources目录下。 - 处理异常和默认值:始终使用
try-with-resources来确保流被正确关闭,使用props.getProperty("key", "default_value")来避免因键不存在而导致的NullPointerException。 - 路径管理:避免在代码中硬编码文件路径,对于
FileInputStream,可以通过环境变量、系统属性或配置文件来指定配置文件的路径,以提高灵活性。 - 考虑更高级的配置库:对于复杂的应用,
java.util.Properties可能功能有限,可以考虑使用更强大的库,如:- Apache Commons Configuration:支持多种配置源(Properties, XML, JSON, 环境变量等)并能自动合并。
- Spring Boot
@ConfigurationProperties:如果你在使用 Spring Boot,这是最佳实践,它可以将配置文件(application.yml/application.properties)中的属性自动绑定到类型安全的 Java Bean 上。
希望这份详细的指南能帮助你更好地理解和使用 Java 中的 Properties 文件加载!
