【问题标题】:Unicode input in a console application in JavaJava 控制台应用程序中的 Unicode 输入
【发布时间】:2012-01-29 22:36:33
【问题描述】:

我一直在尝试在我的 Java 应用程序中为小型实用程序 sn-p 检索“unicode 用户输入”。问题是,它似乎正在“开箱即用”的 Ubuntu 上运行,我猜它在 UTF-8 上具有操作系统范围的编码,但在从“cmd”运行时在 Windows 上不起作用。考虑的代码如下:

public class SerTest {

    public static void main(String[] args) throws Exception {
        testUnicode();
    }

    public static void testUnicode() throws Exception {
        System.out.println("Default charset: " +
           Charset.defaultCharset().name());
        BufferedReader in  =
           new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
        System.out.printf("Enter 'абвгд эюя': ");
        String line = in.readLine();
        String s = "абвгд эюя";
        byte[] sBytes = s.getBytes();
        System.out.println("strg bytes: " + Arrays.toString(sBytes));
        byte[] lineBytes = line.getBytes();
        System.out.println("line bytes: " + Arrays.toString(lineBytes));
        PrintStream out = new PrintStream(System.out, true, "UTF-8");
        out.print("--->" + s + "<----\n");
        out.print("--->" + line + "<----\n");
    }

}

在 Ubuntu 上的输出(无需对配置进行任何更改):

me@host> javac SerTest.java  && java SerTest
Default charset: UTF-8
Enter 'абвгд эюя': абвгд эюя
strg bytes: [-48, -80, -48, -79, -48, -78, -48, -77, -48, -76, 32, -47, -115, -47, -114, -47, -113]
line bytes: [-48, -80, -48, -79, -48, -78, -48, -77, -48, -76, 32, -47, -115, -47, -114, -47, -113]
--->абвгд эюя<----
--->абвгд эюя<----

Windows CMD 提示符下的输出(不受 JAVA_TOOL_OPTIONS 影响):

E:\>chcp 65001
Active code page: 65001

E:\>java -Dfile.encoding=utf8 SerTest
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=utf8
Default charset: UTF-8
Enter 'абвгд эюя': юя': ': абвгд эюя
strg bytes: [-48, -80, -48, -79, -48, -78, -48, -77, -48, -76, 32, -47, -115, -47, -114, -47, -113]
Exception in thread "main" java.lang.NullPointerException
        at SerTest.testUnicode(SerTest.java:26) # byte[] lineBytes = line.getBytes();
        at SerTest.main(SerTest.java:15)

Eclipse 控制台中的输出(使用 JAVA_TOOL_OPTIONS 后):

Default charset: UTF-8
Enter 'абвгд эюя': абвгд эюя
strg bytes: [-48, -80, -48, -79, -48, -78, -48, -77, -48, -76, 32, -47, -115, -47, -114, -47, -113]
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=utf8
line bytes: [-48, -80, -48, -79, -48, -78, -48, -77, -48, -76, 32, -47, -115, -47, -114, -47, -113]
--->абвгд эюя<----
--->абвгд эюя<----

在 Eclipse 控制台上,它可以正常工作,因为我添加了一个系统范围的环境变量 (JAVA_TOOL_OPTIONS),如果可能的话,我希望避免使用它。

Eclipse 控制台中的输出(删除 JAVA_TOOL_OPTIONS 之后):

Default charset: UTF-8
Enter 'абвгд эюя': абвгд эюя
strg bytes: [-48, -80, -48, -79, -48, -78, -48, -77, -48, -76, 32, -47, -115, -47, -114, -47, -113]
line bytes: [-61, -112, -62, -80, -61, -112, -62, -79, -61, -112, -62, -78, -61, -112, -62, -77, -61, -112, -62, -76, 32, -61, -111, -17, -65, -67, -61, -111, -59, -67, -61, -111, -17, -65, -67]
--->абвгд эюя<----
--->абвгд �ю�<----

所以我的问题是:究竟是怎么回事?需要进行哪些代码更改才能确保此 sn-p 适用于各种“Unicode”输入?

很抱歉这个冗长的问题,并在此先感谢您,
佐助

【问题讨论】:

    标签: java unicode console-application


    【解决方案1】:

    一些注意事项:

    • -Dfile.encoding=utf8not supported,可能会导致意想不到的副作用:

    J2SE 平台规范不需要“file.encoding”属性;它是 Sun 实现的内部细节,不应由用户代码检查或修改。它也是只读的;技术上不可能支持在命令行上或在程序执行期间的任何其他时间将此属性设置为任意值。

    • Console 类将检测并使用终端编码,但在 Windows 上不支持 65001 (UTF-8) - 至少,我上次尝试时不是这样

    我认为,将 Unicode 与 cmd.exe 结合使用的正确且有记录的方法是使用 WriteConsoleWReadConsoleW

    当我看到这个时,我写了几篇博客文章:

    【讨论】:

    • 啊,所以在编写 Windows 命令行应用程序时基本上没有理智的方式来读取/写入 unicode 内容?在这里,我正在调试来自 sun.* 包的 UTFEncoder/Decoder...
    • 据我所知,没有跨平台的方式。那里有许多 3rd 方控制台库,它们可能为您提供一个通用接口,可用于所有平台的写入,但我不知道它们对 I18N 的支持程度如何。
    • 谢谢。我想我将不得不研究一些浮动的诅咒实现(比如这个:slashie.net/libjcsi),并希望他们以一种理智的方式处理 unicode。接受!
    【解决方案2】:

    当您尝试调用Arrays.toString(lineBytes) 时会抛出NPE,这意味着lineBytes 为空。

    lineBytes 持有价值:line.getBytes()。只有在 UnsupportedEncodingException 被抛出时,getBytes() 才能返回 null。

    它发生在 windows 上,因为 windows 命令提示符默认不支持 unicode。这适用于 Ubuntu,因为它的命令提示符完全启用了 unicode。它部分适用于 eclipse,因为 Eclipse 的控制台窗口是一个 java 组件,它支持 unicode 输入并使用 JAVA_TOOL_OPTIONS 输出。

    底线是您希望将 Windows 命令提示配置为能够使用 unicode 字符。我看到了几个关于这个话题的讨论。请看这个:Unicode characters in Windows command line - how?

    我希望这会对你有所帮助。

    【讨论】:

    • 这就是要走的路。我认为没有人可以在这个答案中添加任何内容。
    • 感谢您的回复。一些澄清:NPE 是因为在line 上调用getBytes(),这意味着line 是NULL,这没有多大意义。我可以确认没有抛出UnsupportedEncodingException(至少我没有看到)。最后,我尝试了链接线程中提到的建议,结果相同。知道这里可能出了什么问题吗?
    • @sasuke,我认为你错了。查看您的堆栈跟踪:在 SerTest.testUnicode(SerTest.java:26)line.getBytes();在 SerTest.main(SerTest.java:15) 处,这意味着 main() 和抛出 NPE 的点之间有 11 行。这正是byte[] lineBytes = line.getBytes();
    • 嗨,Alex,我可以说它是 line.getBytes(),因为我添加了一个新行 System.out.println(line),它给了我 null。此外,如果您使用的是 Windows,如果您可以运行相同的代码并让我知道它是否适合您,我将不胜感激。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2010-09-29
    • 1970-01-01
    • 2011-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-17
    相关资源
    最近更新 更多