杰瑞科技汇

Java properties属性如何正确读写与编码?

Properties 类在 Java 中是一个非常核心和常用的类,它继承自 Hashtable,主要用于读取和写入应用程序的配置参数,这些参数通常以“键=值”的形式存储在 .properties 文件中。

Java properties属性如何正确读写与编码?-图1
(图片来源网络,侵删)

下面我将从以下几个方面进行详细说明:

  1. Properties 类简介
  2. 核心特点
  3. 常用方法
  4. 实战操作(读取、写入、更新属性文件)
  5. 最佳实践与注意事项

Properties 类简介

java.util.Properties 类是 java.util.Hashtable 的子类,它提供了几个核心功能:

  • .properties 文件加载属性: 可以轻松地从外部配置文件中读取键值对。
  • .properties 文件存储属性: 可以将内存中的属性集合保存到文件中。
  • 在内存中管理属性: 可以像操作 Map 一样,在程序中增删改查属性。

这种机制使得应用程序的配置与代码分离,提高了程序的灵活性和可维护性,当需要修改配置时,只需修改 .properties 文件,而无需重新编译 Java 代码。


核心特点

  • 键和值都是字符串类型:Hashtable 不同,Properties 要求键和值都必须是 String 类型,如果你尝试存入非 String 类型的键或值,它会自动调用 toString() 方法。
  • 支持有序读取: 从 Java 8 开始,Properties 类的 store()load() 方法可以保证属性的写入和读取顺序与它们在 Properties 对象中的迭代顺序一致(在 JDK 9 中得到改进和保证)。
  • 支持默认属性: 可以在创建 Properties 对象时指定另一个 Properties 对象作为“默认属性”,当查找一个键时,如果当前对象中不存在,会自动去默认属性中查找。
  • 支持注释和特殊字符: 虽然不是官方标准,但大多数 .properties 文件解析器都支持以 或 开头的行作为注释。Properties 类本身也支持在 store() 方法中写入时间戳等注释信息。

常用方法

Properties 类的方法可以分为三大类:从文件加载、向文件存储、内存操作。

Java properties属性如何正确读写与编码?-图2
(图片来源网络,侵删)

文件加载

  • load(InputStream inStream): 从字节输入流中加载属性列表。
  • load(Reader reader): 从字符输入流中加载属性列表(推荐用于处理文本文件,可以指定字符编码)。
  • loadFromXML(InputStream in): 从 XML 格式的输入流中加载属性列表。

文件存储

  • store(OutputStream out, String comments): 将属性列表以适合使用 load(InputStream) 方法加载到 Properties 表中的格式写入输出流。
  • store(Writer writer, String comments): 将属性列表写入字符输出流(推荐)。
  • storeToXML(OutputStream os, String comment): 将属性列表以 XML 格式写入输出流。

内存操作

这些方法与 Hashtable 类似。

  • String getProperty(String key): 用指定的键在此属性列表中搜索属性,如果找不到,则返回 null
  • String getProperty(String key, String defaultValue): 用指定的键在此属性列表中搜索属性,如果找不到,则返回指定的默认值。
  • Object setProperty(String key, String value): 调用 Hashtableput 方法,它返回此属性列表中指定键对应的旧值,如果没有该键,则返回 null
  • void list(PrintStream out): 将属性列表打印到指定的输出流。
  • void list(PrintWriter out): 将属性列表打印到指定的输出流。
  • Enumeration<?> propertyNames(): 返回此属性列表中所有键的枚举,包括在不同层次结构中默认属性列表中未覆盖的键。

实战操作

假设我们有一个配置文件 config.properties

config.properties 文件内容

# Database Configuration
db.url=jdbc:mysql://localhost:3306/mydb
db.username=admin
db.password=secret123
# Application Settings
app.name=My Cool Application
app.version=1.0.0

示例 1:读取属性文件

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class ReadPropertiesExample {
    public static void main(String[] args) {
        // 1. 创建一个 Properties 对象
        Properties prop = new Properties();
        // 使用 try-with-resources 自动关闭资源,这是最佳实践
        try (InputStream input = new FileInputStream("config.properties")) {
            // 2. 加载 properties 文件
            prop.load(input);
            // 3. 获取属性值
            String dbUrl = prop.getProperty("db.url");
            String username = prop.getProperty("db.username");
            String password = prop.getProperty("db.password");
            String appName = prop.getProperty("app.name", "Default App"); // 提供默认值
            System.out.println("Database URL: " + dbUrl);
            System.out.println("Username: " + username);
            System.out.println("Password: " + password);
            System.out.println("Application Name: " + appName);
            // 如果键不存在,会返回 null
            String nonExistentKey = prop.getProperty("non.existent.key");
            System.out.println("Non-existent key: " + nonExistentKey);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

示例 2:写入和更新属性文件

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;
public class WritePropertiesExample {
    public static void main(String[] args) {
        // 1. 创建一个 Properties 对象
        Properties prop = new Properties();
        // 2. 设置一些属性
        prop.setProperty("app.name", "My Updated Application");
        prop.setProperty("app.version", "2.0.0");
        prop.setProperty("debug.mode", "true");
        // 3. 将属性写入文件
        // 同样使用 try-with-resources
        try (OutputStream output = new FileOutputStream("config.properties")) {
            // 第二个参数是写入文件时的注释,可以为 null
            prop.store(output, "Application Configuration File - Updated");
            System.out.println("Properties file updated successfully!");
        } catch (IOException io) {
            io.printStackTrace();
        }
    }
}

运行此代码后,config.properties 文件内容将被更新为:

#Application Configuration File - Updated
#Mon Nov 20 10:30:00 CST 2025
app.name=My Updated Application
app.version=2.0.0
debug.mode=true
# Database Configuration
db.url=jdbc:mysql://localhost:3306/mydb
db.username=admin
db.password=secret123
# Application Settings
app.name=My Cool Application
app.version=1.0.0

注意: store() 方法会保留文件中原有的内容,并将新属性追加到文件末尾,如果需要完全覆盖,请确保文件是空的或先删除旧文件。

Java properties属性如何正确读写与编码?-图3
(图片来源网络,侵删)

最佳实践与注意事项

  1. 资源管理(使用 try-with-resources)FileInputStreamFileOutputStream 都是需要手动关闭的资源。强烈推荐使用 try-with-resources 语句,它可以自动关闭资源,即使在发生异常时也能保证资源被正确释放,避免内存泄漏。

  2. 文件路径问题

    • 绝对路径new FileInputStream("C:/projects/myapp/config.properties"),这种方式硬编码了路径,降低了程序的可移植性。
    • 相对路径new FileInputStream("config.properties"),路径是相对于当前工作目录的,在 IDE(如 IntelliJ IDEA, Eclipse)中运行时,当前工作目录通常是项目根目录,但在打包成 JAR 或部署到服务器后,当前工作目录可能会改变,导致找不到文件。
    • 推荐做法:从类路径加载,将 .properties 文件放在 src/main/resources 目录下(Maven/Gradle 项目),它会被打包到最终的 JAR 或 WAR 文件的根目录中,然后使用 ClassLoader 来加载:
    // 推荐方式:从类路径加载
    try (InputStream input = ReadPropertiesExample.class.getClassLoader().getResourceAsStream("config.properties")) {
        if (input == null) {
            System.out.println("Sorry, unable to find config.properties");
            return;
        }
        prop.load(input);
        // ... 其余代码
    } catch (IOException ex) {
        ex.printStackTrace();
    }
  3. 字符编码load(InputStream) 方法使用平台默认的字符编码(如 Windows 上的 GBK,Linux 上的 UTF-8)来读取文件,如果配置文件不是默认编码,可能会导致乱码。推荐使用 load(Reader),并明确指定字符编码(如 InputStreamReader)。

    // 处理编码问题的正确方式
    try (InputStreamReader reader = new InputStreamReader(
            new FileInputStream("config.properties"), "UTF-8")) {
        prop.load(reader);
    }
  4. 线程安全Properties 对象本身不是线程安全的,如果多个线程同时读写同一个 Properties 实例,需要进行同步控制(例如使用 synchronized 块)。

  5. 不要将敏感信息存入明文:像数据库密码、API 密钥等敏感信息绝对不要直接写在 .properties 文件中,应该考虑使用环境变量、加密的配置文件或专门的配置管理服务(如 HashiCorp Vault, Spring Cloud Config)。


Properties 类是 Java 开发中处理配置文件的基石,它的核心价值在于:

  • 解耦:将配置与代码分离。
  • 灵活:无需重新编译即可修改配置。
  • 简单:API 设计直观,易于使用。

记住它的几个关键点:键值对都是字符串、推荐使用 try-with-resources、注意文件路径和字符编码问题,并遵循最佳实践,你就能在项目中得心应手地使用它。

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