如果您面临同样的问题,并且您的字符集包含在 ANSI 测试编码(代码页 1252 或“ISO 8859-1”)中,您可以使用该编码来暂时规避 UTF-8 问题,但是UTF-8 是现代标准,涵盖了最终本地化的每个脚本。
我正在创建一个应用程序,它必须从控制台读取包含重音字符的用户输入。根据我在网上阅读的内容,现代控制台能够处理重音字符输出,并正确编码输入,即使它们在发送命令之前显示为
?
。
PS C:\> echo ?
ü
Ps C:\>
注意:此行为在命令提示符中不可重现。在 Windows 终端中运行时,命令提示符似乎也在发送之前正确显示重音字符。
但是,当运行下面的测试代码时:
package com.test.outputtest;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.nio.file.*;
public class OutputTest {
public static void main(String[] args) {
// Set I/O to use UTF-8
System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out), true, StandardCharsets.UTF_8));
// Create the response listener
Scanner input = new Scanner(System.in, StandardCharsets.UTF_8);
System.out.println(Arrays.toString("èéëê".getBytes(StandardCharsets.UTF_8)));
String temp = input.nextLine();
System.out.println(Arrays.toString(temp.getBytes(StandardCharsets.UTF_8)));
}
}
这是输出(构建工件“app.jar”之后):
PS C:\Users\[name]\Desktop\output_test> chcp 65001
Active code page: 65001
PS C:\Users\[name]\Desktop\output_test> java "-Dfile.encoding=UTF-8" -jar app.jar
[-61, -88, -61, -87, -61, -85, -61, -86]
èéëê
[0, 0, 0, 0]
第一个字节数组来自预先写好的字符串,第二个数组是输入字符串的字节。
echo
正确输出重音这一事实让我相信这是一个编译器错误,但我不确定如何修复它。我试过用Scanner
替换Console
,这给了我同样的错误。
在 IntelliJ 内部运行时,在终端中输入 ü 时可以正常读取它。这也是我怀疑编译时有问题的一个原因。 当使用命令提示符而不是 PowerShell 运行时,会发生同样的错误。
注意:我正在使用运行 PowerShell 的 Windows 终端和 IntelliJ Idea Community Edition 2021.3。除了工件构建文件路径和其他一些项目特定的文件路径之外,我还没有编辑
.xml
文件。
我可以重现你的问题,但我看不出你的代码有什么问题,而且我没有简单的解决方案。令人难以置信的是,即使使用最新版本的 Java(18、19、20),从 Windows 控制台读取 UTF-8 字符似乎仍然存在问题。
这在 JDK bug JDK-8295672 中有正式记录,提供了一个更好的替代方法来读取 System.in,这是开放且未解决的。它指出(加上我的重点):
Reading
是有问题的,因为它是一个编码为 主机的编码。对于 JEP 400,有些情况下 默认编码 (UTF-8) 和主机的本机编码不同。读书 字节正确,用户必须转换字节 native-to-default,这似乎是基本使用的障碍。 提供更好的访问方式(不考虑编码内容) 会很合适。System.in
因此将默认字符集设置为 UTF-8 并不能解决问题,因为“主机的本机编码” 不是 UTF-8,您对此无能为力(至少对于 cmd.exe和 PowerShell 在 Windows 上)。
备注:
Scanner
。请参阅如何使用 Java Native Access 从打开的 Windows 控制台(命令提示符)读取内容以帮助您入门。另请参阅 JNA WinCon
接口的 Javadoc,尤其是ReadConsoleInput()
。在整个标准 Java API 中对 UTF-8 进行标准化,除了 控制台 I/O.