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; } }
运行结果
挑战 挑战 挑战 挑战 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
相关产品推荐
相关产品推荐

