杰瑞科技汇

Java如何读取properties文件?

核心概念:java.util.Properties

无论使用哪种方法,最终都会用到 java.util.Properties 这个核心类,它是一个 Hashtable 的子类,专门用于处理键值对形式的配置信息,键和值都是 String 类型。

Java如何读取properties文件?-图1
(图片来源网络,侵删)

它的主要方法包括:

  • load(InputStream inStream): 从输入流中加载属性列表。
  • load(Reader reader): 从字符输入流中加载属性列表(推荐用于处理非 ASCII 字符)。
  • getProperty(String key): 用指定的键在此属性列表中搜索属性。
  • getProperty(String key, String defaultValue): 同上,如果找不到键,则返回默认值。
  • setProperty(String key, String value): 设置一个属性,如果已存在则覆盖。
  • store(OutputStream out, String comments): 将属性列表写入输出流。
  • store(Writer writer, String comments): 将属性列表写入字符输出流。

使用 ClassLoader (最经典、最常用)

这是最传统和推荐的方法,因为它能利用 Java 类路径(Classpath)机制,自动从 src/main/resources 目录(或 Maven/Gradle 的相应目录)下查找文件。

适用场景:当 .properties 文件作为项目资源被打包到 JAR 或 WAR 文件中时。

步骤

Java如何读取properties文件?-图2
(图片来源网络,侵删)
  1. .properties 文件放在项目的类路径下,src/main/resources/config.properties
  2. 在 Java 代码中,通过 ClassLoader 获取文件的输入流。
  3. 使用 Properties 对象的 load() 方法加载流。
  4. 通过 getProperty() 方法获取值。

代码示例:

假设我们有一个文件 src/main/resources/config.properties:

# Database Configuration
db.url=jdbc:mysql://localhost:3306/mydb
db.username=admin
db.password=secret
app.name=MyAwesomeApp
app.version=1.0.0

对应的 Java 代码:

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class PropertiesReaderExample {
    public static void main(String[] args) {
        // 1. 创建 Properties 对象
        Properties props = new Properties();
        // 使用 try-with-resources 确保 InputStream 被自动关闭
        try (InputStream input = PropertiesReaderExample.class.getClassLoader().getResourceAsStream("config.properties")) {
            // 2. 检查文件是否存在
            if (input == null) {
                System.out.println("Sorry, unable to find config.properties");
                return;
            }
            // 3. 加载属性文件
            props.load(input);
            // 4. 获取属性值
            String dbUrl = props.getProperty("db.url");
            String username = props.getProperty("db.username");
            String password = props.getProperty("db.password");
            String appName = props.getProperty("app.name", "DefaultApp"); // 提供默认值
            String appVersion = props.getProperty("app.version");
            // 打印结果
            System.out.println("App Name: " + appName);
            System.out.println("App Version: " + appVersion);
            System.out.println("Database URL: " + dbUrl);
            System.out.println("Database User: " + username);
            System.out.println("Database Password: " + password);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

优点:

Java如何读取properties文件?-图3
(图片来源网络,侵删)
  • 简单、直接。
  • 文件作为资源,打包和部署非常方便。
  • 是 Java 生态中最标准的做法。

缺点:

  • 只能读取类路径下的文件,无法直接读取文件系统中的任意文件(除非手动设置类路径)。

使用 Files (Java 7+,现代 NIO 方式)

如果你的 .properties 文件位于文件系统的任意位置,并且你使用的是 Java 7 或更高版本,可以使用 java.nio.file.Filesjava.nio.charset.StandardCharsets 来读取。

适用场景:当配置文件位于项目外部(如 /etc/myapp/config.properties)时。

代码示例:

假设文件在 C:/temp/config.properties

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Properties;
public class FilesPropertiesReader {
    public static void main(String[] args) {
        // 1. 定义文件路径
        Path path = Paths.get("C:/temp/config.properties");
        // 2. 创建 Properties 对象
        Properties props = new Properties();
        try {
            // 3. 使用 Files.newBufferedReader 读取文件
            //    try-with-resources 确保 Reader 被自动关闭
            try (var reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
                // 4. 加载属性
                props.load(reader);
                // 5. 获取并打印属性值
                System.out.println("App Name: " + props.getProperty("app.name"));
                System.out.println("Database URL: " + props.getProperty("db.url"));
            }
        } catch (IOException e) {
            System.err.println("Error reading properties file: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

优点:

  • 灵活性高,可以读取文件系统上任何位置的文件。
  • 使用 NIO API,性能更好,对文件编码处理更优雅(明确指定 UTF-8)。

缺点:

  • 需要硬编码或通过参数传入文件路径,降低了可移植性。
  • 相比 ClassLoader 方法,代码稍显繁琐。

使用 ResourceBundle (国际化场景)

ResourceBundle 专门用于国际化(i18n),但它也可以非常方便地加载 .properties 文件,它会根据默认区域设置或指定的区域设置来加载不同的属性文件(如 config_en_US.properties)。

适用场景:需要多语言支持时,或者只是想利用其资源加载机制。

命名规则:

  • 基础文件名(如 config
  • 语言代码(可选,如 en
  • 国家/地区代码(可选,如 US
  • 后缀 .properties

config.properties (默认), config_zh_CN.properties (简体中文)。

代码示例:

假设文件 config.propertiessrc/main/resources 下。

import java.util.ResourceBundle;
public class ResourceBundleExample {
    public static void main(String[] args) {
        // 1. 获取资源包
        //    文件名不带 .properties 后缀,也不包含路径
        //    ResourceBundle 会自动从类路径下查找
        ResourceBundle labels = ResourceBundle.getBundle("config");
        // 2. 获取属性值
        //    如果键不存在,会抛出 MissingResourceException
        try {
            String appName = labels.getString("app.name");
            String dbUrl = labels.getString("db.url");
            System.out.println("App Name from ResourceBundle: " + appName);
            System.out.println("Database URL from ResourceBundle: " + dbUrl);
            // 尝试获取一个不存在的键
            // String nonExistent = labels.getString("non.existent.key"); // 会抛出异常
        } catch (Exception e) {
            System.err.println("Error: " + e.getMessage());
        }
    }
}

优点:

  • 专为国际化设计,可以轻松切换不同语言的配置。
  • 自动处理资源加载,代码简洁。
  • 性能较好,加载后会被缓存。

缺点:

  • 不适合需要动态修改配置的场景,因为 ResourceBundle 是只读的。
  • 键不存在时会抛出异常,不如 Properties.getProperty() 的默认值机制灵活。

总结与最佳实践

方法 适用场景 优点 缺点
ClassLoader 标准项目资源(JAR/WAR 内部) 最标准、最简单、推荐 只能读类路径下文件
Files (NIO) 外部文件(任意文件系统路径) 非常灵活,编码处理清晰 路径硬编码,可移植性差
ResourceBundle 国际化(i18n) 或只读配置 专为多语言设计,性能好 只读,无默认值机制

最佳实践建议:

  1. 首选 ClassLoader 方法:对于绝大多数 Java 项目,将配置文件放在 src/main/resources 目录下,并使用 ClassLoader.getResourceAsStream() 是最健壮、最标准的做法,它确保了配置文件与应用程序一同打包和部署。

  2. 处理编码问题.properties 文件中包含非 ASCII 字符(如中文),请务必使用 InputStreamReader 包装 InputStream 并指定正确的字符集(如 UTF-8),或者直接使用 Properties.load(Reader) 方法。

    // 更好的编码处理方式
    try (InputStream input = getClass().getClassLoader().getResourceAsStream("config.properties");
         Reader reader = new InputStreamReader(input, StandardCharsets.UTF_8)) {
        props.load(reader);
    }
  3. 提供默认值:使用 props.getProperty("key", "default_value") 可以在配置文件中缺少某个键时避免 NullPointerException,使程序更健壮。

  4. 处理异常:始终对 IOException 进行捕获和处理,不要让程序因读取配置失败而意外终止。

  5. 考虑使用更强大的库:对于大型或复杂的应用,可以考虑使用更高级的配置库,如 Apache Commons ConfigurationSpring Boot 的 @ConfigurationProperties,它们提供了类型安全的绑定、属性自动刷新、环境变量集成等更强大的功能。

分享:
扫描分享到社交APP
上一篇
下一篇