properties.load()读utf-8中文配置会乱码,应改用load(reader)并指定utf-8编码;setproperty()是类型安全的专用方法,put()易致classcastexception;store()覆盖写入且不保留格式;properties非线程安全,需外部同步。

Properties.load() 读取配置文件时中文乱码怎么办
Java 的 Properties 默认用 ISO-8859-1 解码,遇到 UTF-8 编码的中文配置文件,load(InputStream) 会把中文变成问号或方块。这不是文件写错了,是读法不对。
- 用
load(Reader)替代load(InputStream),显式指定编码:try (Reader reader = Files.newBufferedReader(Paths.get("config.properties"), StandardCharsets.UTF_8)) { props.load(reader); } - 别用
new FileReader("config.properties")—— 它依赖系统默认编码,Windows 和 Linux 表现不一致 - 如果必须用
load(InputStream)(比如老项目兼容),得自己转码:先用 UTF-8 读字节流,再按 ISO-8859-1 转成字符串传给load(),但容易出错,不推荐
setProperty() 和 put() 都能存值,该选哪个
setProperty(String, String) 是 Properties 的专用方法,put(Object, Object) 继承自 Hashtable。表面都能塞键值,但行为差异明显。
-
setProperty()会自动对 key 和 value 做String.valueOf()转换,并且在保存时对特殊字符(如=、:、空格)做转义;put()不处理,直接存 Object 引用,后续store()可能抛ClassCastException - 所有 key 和 value 必须是
String类型,这是Properties的契约。用put(123, true)看似能过编译,但调用store()时会失败 - 实际开发中只用
setProperty(),避免类型混淆和保存异常
store() 写入文件后,注释和原有格式全没了
Properties.store() 是“覆盖写入”,它只保证键值对正确,不保留原文件的空行、注释、键顺序或缩进。这不是 bug,是设计如此。
- 如果需要保留格式(比如运维要手改配置),别用
store(),改用storeToXML()或自行解析/拼接文本 -
store()第二个参数是 header 注释,只写在文件最开头,且自动加#,不能插在中间 - 想追加新配置?
Properties没有原生 append 模式,得先load()全量,再setProperty(),最后store()全量覆盖
Properties 在多线程环境下安全吗
不安全。虽然 Properties 继承自 Hashtable(方法加了 synchronized),但它的典型使用流程——load() → 修改 → store()——是三个独立操作,中间没锁保护。
- 两个线程同时
load()同一个文件,各自修改后store(),后写入的会完全覆盖前者的改动 - 如果只是读多写少,可用
Collections.synchronizedMap(new Properties())包一层,但无法解决 load/store 的原子性问题 - 真正可靠的方案是:写操作加外部锁(比如
synchronized(fileLock)),或改用java.util.prefs.Preferences、Spring 的@ConfigurationProperties等更现代的配置管理方式
store() 的覆盖行为和缺乏事务支持,最容易被当成“安全操作”忽略。










