You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows环境下Java字符串码点异常,重启后输出乱码问题排查

问题描述

我编写了一段Java代码用于实现Unicode转义处理与Base64编解码功能。首次运行时程序输出正常,但通过ProcessBuilder重启应用后,字符串输出全部变为"??",尽管码点值显示正确,希望得到排查思路。

代码实现

package edu.practice.zapper;

import java.io.IOException;
import java.lang.ProcessBuilder.Redirect;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;

public class Zapper {
    private static final String UNICODE_START = "&#";
    private static final String UNICODE_END = ";";
    private String input;

    public Zapper() {
    }

    public String unicodePrint(String input) {
        if (input != null && !input.isEmpty()) {
            StringBuilder sbTitle = new StringBuilder();
            System.err.println(input);
            input.codePoints().forEach(codepoint->{
                if (codepoint > 127) {
                    sbTitle.append(UNICODE_START);
                    sbTitle.append(codepoint);
                    sbTitle.append(UNICODE_END);
                } else {
                    sbTitle.appendCodePoint(codepoint);
                }
            });
            input = sbTitle.toString();
            System.err.println(input);
        }
        return input;
    }

    public static void main(String[] args) {
        Zapper z = new Zapper();
        z.input = "挑战";
        if(args.length > 0) {
            System.out.println("Restarting:%s :%d :%d".formatted(z.input,z.input.codePointAt(0),z.input.codePointAt(1)));
        }
        String encodeString = Base64.getEncoder().encodeToString(z.input.getBytes());
        byte[] decodeBytes = Base64.getDecoder().decode(encodeString);
        String decodeStringU = new String(decodeBytes,Charset.forName("UTF-8"));
        String decodeString = new String(decodeBytes);
        z.unicodePrint(decodeStringU);
        z.unicodePrint(decodeString);
        if(args.length < 1) {
            restartApplication();
        }
    }
    private static Process restartApplication() {
        Process process = null;
        while (process == null) {
            List<String> command = new ArrayList<>();
            command.add("java");
            command.add("-Ddebugging=false");
            command.add("-DdebugUnit=None");
            command.add("-jar");
            command.add("zapper-1-jar-with-dependencies.jar");
            command.add("restarted");
            ProcessBuilder pb = new ProcessBuilder(command);
            pb.redirectOutput(Redirect.INHERIT);
            pb.redirectError(Redirect.INHERIT);
            try {
                process = pb.start();
                Thread.sleep(5_000);
            } catch (IOException | InterruptedException e) {
                System.out.println(e.getMessage());
            }
        }
        return process;
    }
}

运行结果

挑战
&#25361;&#25112;
挑战
&#25361;&#25112;
Restarting:?? :25361 :25112
??
??
??
??
排查思路
  • 强制指定JVM字符集
    重启后的进程默认字符集可能与原进程不一致,导致字符串转码错误。在重启命令中添加-Dfile.encoding=UTF-8参数,强制JVM使用UTF-8编码:

    command.add("-Dfile.encoding=UTF-8");
    
  • 明确编码时的字符集
    代码中z.input.getBytes()和new String(decodeBytes)依赖JVM默认字符集,改为明确指定UTF-8避免编码差异:

    // 编码时指定UTF-8
    String encodeString = Base64.getEncoder().encodeToString(z.input.getBytes(StandardCharsets.UTF_8));
    // 解码时统一用UTF-8
    String decodeString = new String(decodeBytes, StandardCharsets.UTF_8);
    
  • 验证控制台输出编码
    即使字符串本身正确,控制台的输出编码不匹配也会显示"??"。可以将输出重定向到文件,查看文件的字符编码是否正确,或者直接打印当前JVM的字符集配置:

    System.out.println("当前字符集:" + System.getProperty("file.encoding"));
    
  • 检查进程环境变量
    ProcessBuilder启动的进程可能继承了不同的环境变量,导致字符集配置变化。可以在重启前后打印环境变量中的编码相关配置,对比差异。

内容的提问来源于stack exchange,提问作者PatK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 13:17:42