杰瑞科技汇

Java Properties类如何高效读写配置文件?

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

Java Properties类如何高效读写配置文件?-图1
(图片来源网络,侵删)

Properties 类的核心概念

Properties 类本质上是一个键值对的集合,类似于 HashMap<String, String>,但它有几个关键特性:

  1. 键和值都是字符串类型:与 HashMap 可以存储任意类型的键和值不同,Properties 的键和值都强制要求是 String 类型。
  2. 持久化存储Properties 类提供了非常方便的方法,可以将键值对直接写入 .properties 文件,也可以从 .properties 文件中读取。
  3. 线程安全(部分):虽然 Properties 继承自 Hashtable(线程安全),但许多常用方法(如 load()store())本身不是线程安全的,在多线程环境中使用时仍需注意同步问题。
  4. 处理注释和有序性.properties 文件可以包含注释(以 或 开头),并且键值对的顺序是有意义的。Properties 类在读写时会保留这些特性。

主要构造方法

Properties 类提供了几个构造方法,最常用的是无参构造方法:

// 创建一个空的 Properties 对象
Properties properties = new Properties();

还可以传入一个默认的 Properties 对象,当查找一个键时,如果当前对象中没有找到,就会在默认对象中查找。

// 创建一个带有默认值的 Properties 对象
Properties defaults = new Properties();
defaults.setProperty("default.db.url", "jdbc:default:database");
Properties properties = new Properties(defaults);

常用方法

Properties 类的方法可以分为以下几类:

Java Properties类如何高效读写配置文件?-图2
(图片来源网络,侵删)

1 与 Map 接口相关的方法(继承自 Hashtable

这些方法与 HashMap 类似,但键和值都是 Object 类型(实际使用时是 String)。

方法 描述
Object setProperty(String key, String value) 设置一个键值对(是 put() 方法的便捷版本)
String getProperty(String key) 根据键获取值,如果键不存在,返回 null
String getProperty(String key, String defaultValue) 根据键获取值,如果键不存在,返回指定的默认值
String remove(Object key) 移除指定的键值对
Set<String> stringPropertyNames() 返回所有键的集合(推荐使用,因为它只返回 String 类型的键)
void clear() 清空所有键值对
int size() 返回键值对的数量

示例:

Properties props = new Properties();
props.setProperty("database.url", "jdbc:mysql://localhost:3306/mydb");
props.setProperty("database.user", "root");
props.setProperty("database.password", "secret");
// 获取值
String url = props.getProperty("database.url"); // "jdbc:mysql://localhost:3306/mydb"
String nonExistentKey = props.getProperty("nonexistent.key"); // null
String nonExistentKeyWithDefault = props.getProperty("nonexistent.key", "default_value"); // "default_value"
// 遍历所有键
System.out.println("--- All Properties ---");
for (String key : props.stringPropertyNames()) {
    System.out.println(key + " = " + props.getProperty(key));
}

2 从输入流加载和到输出流存储

这是 Properties 类最核心的功能,用于与 .properties 文件交互。

方法 描述
void load(InputStream inStream) 从字节输入流中加载属性列表
void load(Reader reader) 从字符输入流中加载属性列表(推荐,能正确处理字符编码)
void store(OutputStream out, String comments) 将属性列表写入字节输出流,可以添加注释
void store(Writer writer, String comments) 将属性列表写入字符输出流(推荐)

完整示例:读写 .properties 文件

这是一个非常典型的使用场景。

Java Properties类如何高效读写配置文件?-图3
(图片来源网络,侵删)

1 创建配置文件 config.properties

在项目的 src 目录下创建一个名为 config.properties 的文件,内容如下:

# Database Configuration
db.url=jdbc:mysql://localhost:3306/test_db
db.user=admin
db.password=123456
# Server Configuration
server.port=8080
server.host=localhost

2 Java 代码:读取 config.properties

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class PropertiesReader {
    public static void main(String[] args) {
        // 1. 创建 Properties 对象
        Properties prop = new Properties();
        // try-with-resources 语句可以自动关闭流
        try (InputStream input = new FileInputStream("src/config.properties")) {
            // 2. 加载 properties 文件
            prop.load(input);
            // 3. 读取属性值
            System.out.println("Database URL: " + prop.getProperty("db.url"));
            System.out.println("Database User: " + prop.getProperty("db.user"));
            System.out.println("Database Password: " + prop.getProperty("db.password"));
            System.out.println("Server Port: " + prop.getProperty("server.port"));
            // 读取一个可能不存在的属性,并提供默认值
            String cacheSize = prop.getProperty("cache.size", "1024");
            System.out.println("Cache Size: " + cacheSize);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

3 Java 代码:写入 config.properties

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;
public class PropertiesWriter {
    public static void main(String[] args) {
        // 1. 创建 Properties 对象
        Properties prop = new Properties();
        // 2. 设置属性
        prop.setProperty("app.name", "MyCoolApp");
        prop.setProperty("app.version", "1.0.0");
        prop.setProperty("logging.level", "INFO");
        // try-with-resources 语句
        try (OutputStream output = new FileOutputStream("src/config.properties")) {
            // 3. 将属性存储到文件
            // 第一个参数是输出流
            // 第二个参数是写入文件顶部的注释,可以为 null
            prop.store(output, "Application Configuration File - Updated");
            System.out.println("Properties file saved successfully!");
        } catch (IOException io) {
            io.printStackTrace();
        }
    }
}

高级用法:从类路径加载资源

在 Java 项目中,配置文件通常被打包在 JAR 或 WAR 文件中,这时,不能使用 FileInputStream,因为它只能从文件系统读取,应该使用 ClassLoader 从类路径(classpath)中加载。

假设 config.propertiessrc/main/resources 目录下,编译后它会在 classpath 的根目录。

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class ClasspathPropertiesLoader {
    public static void main(String[] args) {
        // 使用 ClassLoader 加载资源
        // 这种方式不依赖于文件系统,资源文件可以打包在 JAR 中
        try (InputStream input = ClasspathPropertiesLoader.class.getClassLoader().getResourceAsStream("config.properties")) {
            if (input == null) {
                System.out.println("Sorry, unable to find config.properties");
                return;
            }
            Properties prop = new Properties();
            prop.load(input);
            // 使用属性...
            System.out.println("Loaded from classpath: " + prop.getProperty("db.url"));
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

Properties vs. Map<String, String>

特性 Properties Map<String, String> (如 HashMap)
键/值类型 强制为 String 可以是任何 Object 类型,但通常用 String
持久化 内置支持,可直接读写 .properties 文件 不支持,需要手动实现序列化/反序列化
线程安全 继承自 Hashtable,基础操作是线程安全的,但 load/store 不是 HashMap 不安全;ConcurrentHashMapCollections.synchronizedMap() 可用
主要用途 配置文件管理 通用内存中的键值存储
注释支持 支持,读写 .properties 文件时会保留注释 不支持
  • 何时使用 Properties

    • 当你需要读取或写入标准的 .properties 配置文件时。
    • 当你的配置信息需要持久化存储,并且希望格式清晰、可读性强时。
    • 当配置项的键和值都是字符串时。
  • 何时考虑其他方案?

    • 如果配置结构非常复杂(如嵌套对象、数组),可以考虑使用 JSONXML 文件,并使用如 Jackson、Gson 或 JAXB 等库来解析。
    • 如果只是需要在内存中临时存储一些键值对,并且不需要持久化,使用 HashMap<String, String> 更简单直接。
    • 如果配置项类型不限于字符串(例如需要数字、布尔值),可以考虑使用 YAML 格式(需要第三方库如 SnakeYAML)或自己编写解析逻辑。
分享:
扫描分享到社交APP
上一篇
下一篇