怎样用Java的Properties类读写配置文件

wen java案例 50

Java Properties类深度解析:从入门到精通,轻松读写配置文件

目录导读

  1. 核心概念:Properties类是什么?
  2. 基础操作:如何创建与加载配置文件
  3. 读写实战:Properties的CRUD操作详解
  4. 高级技巧:中文乱码处理与默认值机制
  5. 常见问答:面试官最常问的3个问题
  6. 最佳实践:企业级配置文件管理策略

核心概念:Properties类是什么?

java.util.Properties 是Java标准库中专门用于处理配置文件的工具类,它继承自 Hashtable,以键值对的形式存储配置数据,并提供持久化到文件的能力,在实际开发中,我们通常用它来读写 .properties 格式的配置文件。

怎样用Java的Properties类读写配置文件

特性速览

  • 基于Key-Value存储:每个配置项由键和值组成,用等号()或冒号()分隔。
  • 继承自Hashtable:因此具备线程安全特性,但注意 Propertiesstoreload 方法本身并不是原子操作。
  • 支持默认值:通过构造函数或 getProperty(key, defaultValue) 提供回退机制。
  • 默认编码兼容:但需注意中文存储时可能因编码问题导致乱码。

典型使用场景

  • 数据库连接配置(JDBC URL、用户名、密码)
  • 系统运行参数(日志级别、端口号、缓存策略)
  • 国际化资源文件(配合ResourceBundle使用)

基础操作:如何创建与加载配置文件

第一步:创建Properties对象

Properties props = new Properties();
// 或指定默认值
Properties propsWithDefault = new Properties(new Properties() {{
    setProperty("port", "8080");
    setProperty("env", "production");
}});

第二步:加载配置文件

从文件系统加载
try (FileInputStream fis = new FileInputStream("config.properties")) {
    props.load(fis);
} catch (IOException e) {
    e.printStackTrace();
}
从类路径加载(推荐方式)
try (InputStream is = MyClass.class.getClassLoader().getResourceAsStream("config.properties")) {
    props.load(is);
} catch (IOException e) {
    e.printStackTrace();
}

注意事项load() 方法默认使用ISO 8859-1编码读取文件,如果配置文件包含中文,请参考后文“中文乱码处理”章节。

第三步:遍历配置文件

props.forEach((key, value) -> System.out.println(key + " = " + value));
// 或使用枚举
Enumeration<?> names = props.propertyNames();
while (names.hasMoreElements()) {
    String key = (String) names.nextElement();
    System.out.println(key + " = " + props.getProperty(key));
}

读写实战:Properties的CRUD操作详解

读取配置项

// 读取字符串值
String host = props.getProperty("db.host", "localhost");
// 读取数值(需要手动转换)
int port = Integer.parseInt(props.getProperty("db.port", "3306"));
// 读取布尔值
boolean debug = Boolean.parseBoolean(props.getProperty("debug", "false"));

写入与修改配置

props.setProperty("new.key", "newValue");
props.setProperty("db.port", "3307"); // 修改已有值

持久化到文件

try (FileOutputStream fos = new FileOutputStream("config.properties")) {
    // 包含注释信息
    props.store(fos, "数据库配置 - 最后修改于2025年");
} catch (IOException e) {
    e.printStackTrace();
}

重要store() 方法同样使用ISO 8859-1编码输出,当值包含非拉丁字符时,会被自动转义为Unicode码点(例如中文变成\\u4e2d\\u6587)。

完整示例:配置管理器

public class ConfigManager {
    private Properties props;
    private String filePath;
    public ConfigManager(String filePath) {
        this.filePath = filePath;
        props = new Properties();
        load();
    }
    public void load() {
        try (InputStream input = new FileInputStream(filePath)) {
            props.load(new InputStreamReader(input, "UTF-8"));
        } catch (IOException e) {
            // 文件不存在时使用默认值
            System.err.println("加载配置失败,使用默认值");
        }
    }
    public String get(String key, String defaultValue) {
        return props.getProperty(key, defaultValue);
    }
    public void set(String key, String value) {
        props.setProperty(key, value);
    }
    public void save() {
        try (OutputStream output = new FileOutputStream(filePath)) {
            props.store(new OutputStreamWriter(output, "UTF-8"), null);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

高级技巧:中文乱码处理与默认值机制

中文乱码的终极解决方案

根本原因:load()store()默认使用ISO 8859-1编码,不支持中文。
解决方式:使用Reader/Writer指定UTF-8编码读取写入。

// 读取时使用UTF-8
try (InputStream input = new FileInputStream("config.properties");
     InputStreamReader reader = new InputStreamReader(input, "UTF-8")) {
    props.load(reader);
}
// 写入时使用UTF-8
try (OutputStream output = new FileOutputStream("config.properties");
     OutputStreamWriter writer = new OutputStreamWriter(output, "UTF-8")) {
    props.store(writer, "配置说明(支持中文)");
}

注意:如果已有配置文件使用了ISO 8859-1且包含转义后的中文(\\u4e2d\\u6587),需先手动解码或编写转换工具。

默认值机制:三级回退策略

// 第一级:直接提供的默认值
String value = props.getProperty("key", "default1");
// 第二级:构造时传入的默认Properties
Properties globalDefaults = new Properties();
globalDefaults.setProperty("key", "default2");
Properties appProps = new Properties(globalDefaults);
String value = appProps.getProperty("key"); // 返回"default2"
// 第三级:硬编码常量
public static final String DEFAULT_PORT = "8080";
String port = props.getProperty("port", DEFAULT_PORT);

配置文件的规范化格式

# 注释以井号开头
db.url=jdbc:mysql://localhost:3306/mydb
db.username=root
# 多行值用反斜杠连接
db.description=A database for \
e-commerce system
# 保留转义字符:\t表示制表符
config.special=hello\tworld

常见问答:面试官最常问的3个问题

Q1:Properties和HashMap有什么区别?

A:Properties继承自Hashtable,因此是线程安全的;而HashMap非线程安全,Properties专为配置文件设计,提供load()store()方法直接与文件交互,且支持默认值查找,但注意Properties的Key和Value必须为String类型,而HashMap支持泛型。

Q2:如何从XML文件加载配置?

A:Properties提供了loadFromXML(InputStream in)方法,可以直接解析XML格式的配置文件。

try (InputStream is = new FileInputStream("config.xml")) {
    props.loadFromXML(is);
}

相应的XML格式:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
    <entry key="db.host">localhost</entry>
    <entry key="db.port">3306</entry>
</properties>

Q3:为什么我的配置文件修改后没有生效?

A:常见原因有3个:

  1. 文件路径错误,程序读取的是打包后的classpath路径而非实际部署路径。
  2. 使用了getResourceAsStream()但文件未在构建时复制到输出目录。
  3. 缓存问题:某些框架会将配置缓存到内存中,解决方案:使用绝对路径读取,或框架提供热加载机制(如Spring的@RefreshScope)。

最佳实践:企业级配置文件管理策略

分层配置设计

config/
├── application.properties       # 基础配置
├── application-dev.properties   # 开发环境
├── application-prod.properties  # 生产环境
└── application-local.properties # 本地覆盖(不提交至版本控制)

敏感信息加密

// 使用自定义解密器
public class EncryptedProperties extends Properties {
    @Override
    public synchronized String getProperty(String key) {
        String value = super.getProperty(key);
        if (value != null && value.startsWith("ENC(")) {
            return decrypt(value.substring(4, value.length()-1));
        }
        return value;
    }
}

统一配置加载工具

推荐使用第三方库简化处理,如Apache Commons Configuration或Spring Boot的@ConfigurationProperties,但若需轻量级方案,可参考以下模式:

// 单例模式配置中心
public enum ConfigCenter {
    INSTANCE;
    private Properties props = new Properties();
    ConfigCenter() {
        try (InputStream is = getClass().getResourceAsStream("/app.properties")) {
            props.load(new InputStreamReader(is, "UTF-8"));
        } catch (IOException e) {
            throw new RuntimeException("初始化配置失败", e);
        }
    }
    public String get(String key) { return props.getProperty(key); }
}

版本控制建议

  • .properties 文件加入 .gitignore(若包含密码)
  • 提供 .properties.template 模板文件供开发者参考
  • 使用环境变量或K8s ConfigMap替代敏感配置

延伸阅读:如果要处理更复杂的配置格式(如YAML、JSON、TOML),推荐使用Jackson或SnakeYAML,Properties类虽轻量,但已能覆盖80%的配置文件场景,掌握它相当于掌握了Java配置管理的基石。

抱歉,评论功能暂时关闭!