杰瑞科技汇

Java properties中文乱码如何解决?

Java Properties 文件的编码历史

在 Java 9 之前,.properties 文件一直存在一个“历史遗留问题”:

Java properties中文乱码如何解决?-图1
(图片来源网络,侵删)
  • 默认编码是 ISO-8859-1,而不是我们常用的 UTF-8 或 GBK。
  • ISO-8859-1 是一个单字节编码,它无法直接表示中文字符,中文字符“中”在 UTF-8 中占3个字节,在 ISO-8859-1 中无法被识别。

在 Java 9 之前,处理中文 Properties 文件有几种主流方法,但都伴随着一些不便,从 Java 9 开始,这个问题得到了很好的解决。


Java 9 之前(经典乱码问题)

在 Java 9 之前,如果你直接在 .properties 文件中写入中文,然后在 Java 代码中读取,几乎一定会得到乱码。

问题复现

config.properties 文件内容 (使用 GBK 编码保存):

# 这是一个注释
welcome.message=欢迎使用我们的系统
user.name=张三

PropertiesReader.java 读取代码:

Java properties中文乱码如何解决?-图2
(图片来源网络,侵删)
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) {
        Properties props = new Properties();
        // 使用 try-with-resources 确保 InputStream 被关闭
        try (InputStream input = new FileInputStream("config.properties")) {
            // 加载属性文件
            props.load(input);
            // 获取并打印属性值
            String welcome = props.getProperty("welcome.message");
            String username = props.getProperty("user.name");
            System.out.println("Welcome Message: " + welcome);
            System.out.println("User Name: " + username);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

可能出现的输出 (乱码):

Welcome Message: 欢连使用我们的系统
User Name: 张三

这是因为 props.load(input) 默认使用 ISO-8859-1 解码 GBK 编码的字节流,导致字符解析错误。

Java 9 之前的解决方案

使用 native2ascii 工具 (官方推荐)

native2ascii 是 JDK 自带的一个工具,它的作用就是将包含非 ASCII 字符(如中文)的文本转换为所有字符都用 \uXXXX Unicode 转义序列表示的形式。

Java properties中文乱码如何解决?-图3
(图片来源网络,侵删)

步骤:

  1. 创建原始的 config.properties 文件 (GBK 编码):

    welcome.message=欢迎使用我们的系统
    user.name=张三
  2. 使用 native2ascii 命令转换文件: 打开命令行,进入项目目录,执行以下命令:

    native2ascii -encoding GBK config.properties config_zh_CN.properties
  3. 查看转换后的 config_zh_CN.properties 文件: 它的内容会变成这样:

    welcome.message=\u4F60\u597D\uff0C\u6B22\u8FCE\u4F7F\u7528\u6211\u4EEC\u7684\u7CFB\u7EDF
    user.name=\u5F20\u4E09

    注意:你好,欢迎使用我们的系统 被转换成了 \u4F60\u597D\uff0c\u6B22\u8FCE\u4F7F\u7528\u6211\u4EEC\u7684\u7CFB\u7EDF

  4. 在 Java 代码中读取转换后的文件: 你的 Java 代码无需任何修改,直接读取 config_zh_CN.properties 即可,因为 Properties.load() 能完美处理这种 Unicode 转义格式。

优点:官方标准,兼容性最好。 缺点:需要手动转换步骤,文件可读性差。


Java 9 及之后 (推荐做法)

从 Java 9 开始,Properties 类得到了重大改进,支持指定编码来加载和存储 .properties 文件,这从根本上解决了中文乱码问题,使得我们可以直接使用 UTF-8 编码的 .properties 文件。

新增的方法

  • load(Reader reader): 从字符流(Reader)中加载属性,Reader 可以指定编码(如 InputStreamReader)。
  • store(Writer writer, String comments): 将属性存储到字符流(Writer)中,Writer 可以指定编码(如 OutputStreamWriter)。

解决方案:使用 InputStreamReader 指定编码

config.properties 文件内容 (直接使用 UTF-8 编码保存):

# 这是一个注释
welcome.message=欢迎使用我们的系统
user.name=张三

PropertiesReaderJava9.java 读取代码:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
public class PropertiesReaderJava9 {
    public static void main(String[] args) {
        Properties props = new Properties();
        // 使用 try-with-resources
        try (
            // 1. 创建字节输入流
            FileInputStream fis = new FileInputStream("config.properties");
            // 2. 创建 InputStreamReader,并明确指定编码为 UTF-8
            InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8)
        ) {
            // 3. 使用 load(Reader) 方法加载
            props.load(isr);
            // 获取并打印属性值
            String welcome = props.getProperty("welcome.message");
            String username = props.getProperty("user.name");
            System.out.println("Welcome Message: " + welcome);
            System.out.println("User Name: " + username);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

输出 (正确显示):

Welcome Message: 欢迎使用我们的系统
User Name: 张三

优点

  • 可读性高,方便直接编辑。
  • 无需额外的转换工具,流程更简单。
  • 这是现代 Java 开发的标准做法。

国际化 (i18n) 中的 Properties 文件

在大型应用中,我们通常使用 .properties 文件来实现国际化,为不同语言创建不同的文件。

文件命名规范: basename_language_country.properties

  • basename:基础名称,messages
  • language:语言代码,zh (中文), en (英文)。
  • country:国家/地区代码,CN (中国), TW (台湾), US (美国)。

示例:

  1. messages_zh_CN.properties (简体中文)

    greeting=你好,世界!
  2. messages_en_US.properties (美式英语)

    greeting=Hello, World!

ResourceBundle 使用示例:

ResourceBundle 会根据系统的默认 Locale 自动加载对应的 .properties 文件。

import java.util.Locale;
import java.util.ResourceBundle;
public class I18nExample {
    public static void main(String[] args) {
        // 获取系统默认的 Locale
        Locale defaultLocale = Locale.getDefault();
        System.out.println("Default Locale: " + defaultLocale);
        // 获取指定 basename 的 ResourceBundle
        // ResourceBundler 会自动寻找 messages_zh_CN.properties 或 messages_en_US.properties
        ResourceBundle messages = ResourceBundle.getBundle("messages", defaultLocale);
        // 根据键获取值
        String greeting = messages.getString("greeting");
        System.out.println("Greeting: " + greeting);
        // 手动切换 Locale 进行测试
        System.out.println("\n--- Testing with US Locale ---");
        Locale usLocale = new Locale("en", "US");
        ResourceBundle usMessages = ResourceBundle.getBundle("messages", usLocale);
        System.out.println("Greeting in US: " + usMessages.getString("greeting"));
    }

国际化文件的最佳实践:

  • 统一使用 UTF-8 编码:所有语言的 .properties 文件都应保存为 UTF-8 编码。
  • Java 9+ 环境:确保你的应用在 Java 9 或更高版本上运行,ResourceBundle 会自动处理 UTF-8 编码。
  • 旧版 Java 环境 (Java 8):如果必须在 Java 8 上运行,并且你的 .properties 文件是 UTF-8 编码的,你需要进行一些配置,一种常见的方法是使用一个第三方库,如 ICU4J,它提供了对 UTF-8 .properties 文件的更好支持,或者,你仍然可以使用 native2ascii 工具将所有文件转换为 ASCII 格式。

总结与最佳实践

版本 推荐方法 优点 缺点
Java 9+ 直接使用 UTF-8 编码的 .properties 文件,并用 InputStreamReader 指定编码加载。 文件可读性好,易于维护。
无需转换工具,开发流程顺畅。
是未来的标准。
需要确保所有开发环境都在 Java 9+。
Java 8 及之前 使用 native2ascii 工具将文件转换为 Unicode 转义格式。 兼容所有 Java 版本。
官方解决方案,稳定可靠。
文件可读性差,难以直接编辑。
增加了构建步骤。

最终建议:

  1. 优先升级到 Java 9 或更高版本,这是解决 Properties 中文问题的根本之道。
  2. 在 Java 9+ 环境下
    • 所有 .properties 文件统一使用 UTF-8 编码保存。
    • 在 Java 代码中,使用 new InputStreamReader(inputStream, StandardCharsets.UTF_8) 来读取文件。
    • 在国际化场景中,ResourceBundle 会自动处理。
  3. 如果无法升级到 Java 9+
    • native2ascii 集成到你的构建脚本(如 Maven、Gradle)中,实现自动化转换。
    • 或者,引入第三方库(如 ICU4J)来增强 ResourceBundle 对 UTF-8 的支持。
分享:
扫描分享到社交APP
上一篇
下一篇