【问题标题】:Java standard input encoding Windows cmd, NetbeansJava 标准输入编码 Windows cmd, Netbeans
【发布时间】:2019-07-14 14:39:55
【问题描述】:

如您所知,InputStreamReader 将读取提供的InputStream 并将其字节解码为字符。如果没有指定charset,它将使用默认字符集

我们可以用java.nio.charset.Charset.defaultCharset().displayName()检查这个默认字符集

案例 1。我的 Windows CMD 使用 cp850,但 Java 报告 windows-1252。可以证明键入字符óSystem.in.read() 将按预期报告162。但是,InputStreamReader 将无法对其进行解码,因为它预计将运行 windows-1252,显示 ¢(这是第 162 个 windows-1252 字符)。

案例 2。在 Windows 中,我的 Netbeans 集成终端使用 windows-1252,但 Java 报告 UTF-8。同样,可以证明键入字符óSystem.in.read() 将按预期报告243。但是,InputStreamReader 将无法对其进行解码,因为它预计将运行UTF-8,显示(代码65533)。

案例 3。我的 Debian 机器在 GNOME 和 Netbeans 终端中到处都使用UTF-8。当键入字符 ó 时,System.in.read() 将报告两个字节,195161,它们对应于该字符的 UTF-8 表示。 InputStreamReader 将按预期显示 ó

我想要什么? 有没有办法正确检测所使用的 实际 字符集,以便我可以从命令行读取字符(在 Windows CMD 和 Windows 中的 Netbeans 中)没有特殊情况?

非常感谢。

B 计划:案例 2 可以通过 changing Netbeans file encoding to UTF-8 解决(它也将处理 UTF-8 文件,这是 IDE 在 2019 年应该做的)。案例 1 可以通过将代码页更改为 UTF-8 来解决,但我无法做到这一点。

您可以使用以下程序来测试这些情况。输入两次相同的字符并比较输出。

import java.io.*;
import java.nio.charset.Charset;

public class Prova2 {
    public static void main(String[] args) throws Exception {
        int b;

        System.out.println("Charset.defaultCharset: " + Charset.defaultCharset().displayName());
        System.out.println("I will read the next bytes: ");
        while ((b = System.in.read()) != '\n') {
            System.out.println("I have read this byte: " + b + " (" + (char) b + ")");
        }
        System.out.println("I will read the next chars: ");
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        while ((b = br.read()) != '\n') {
            System.out.println("I have read this char: " + b + " (" + (char) b + ")");
        }
        System.out.println("Thank you.");
    }

}

【问题讨论】:

标签: java windows netbeans encoding utf-8


【解决方案1】:

有没有办法正确检测使用的实际字符集,以便我可以 从命令行读取字符,没有任何特殊情况?

在 Windows 上,您可以在从命令行 using JNA 读取字符时使用 detect (or even set) the code page used。但是,如果使用其他方法来获取控制台输入,则不需要这样做:

  • 不是从System.in 读取,而是使用System.console 来捕获用户输入。这允许将提交的文本作为String 处理,而不是bytes 或chars。这提供了对所有 String 方法的访问,以将控制台输入解释为字节、字符或 UTF-8 数据。
  • 使用这种方法,在从命令行提交输入之前设置合适的代码页至关重要。例如,如果提交俄语字符,则使用 chcp 1251 将代码页设置为 1251。

使用这种方法,只需两行代码即可获得用户输入:

Console console = System.console();
String userInput = console.readLine();

案例 2. 在 Windows 中,我的 Netbeans 集成终端使用 windows-1252...

不要浪费时间尝试让控制台输入在 NetBeans 中工作。 System.console() 将返回 null,并且无法配置其控制台。我怀疑其他 IDE 中也存在类似的限制。无论如何,在 NetBeans 中进行测试并没有提供任何有意义的好处。只需专注于从命令行进行测试。

情况2可以通过将Netbeans文件编码改为UTF-8来解决...

使用下面的方法,项目的编码设置无关紧要。无论编码设置为Windows-1252 还是UTF-8,它都可以工作。

注意事项:

  • 我只在 Windows 上进行了测试,但只要控制台环境设置正确,代码应该可以在其他平台上运行。 (据我所知,使用 chcp 是特定于 Windows 的。)
  • 和你一样,我无法让chcp 65001 处理 Unicode 输入。只需专注于确保可以使用合适的代码页成功读取输入。例如,当使用 OP 中提到的字符(ó¢)进行测试时,使用任何支持这两个字符的代码页都可以。例如:437、850、1252 等。如果应用程序显示正确提交的字符,则一切正常(反之亦然)。

这是代码,主要包括显示控制台输入:

package prova3;

import java.io.Console;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;

public class Prova3 {

    public static void main(String[] args) throws UnsupportedEncodingException {

        Console console = System.console();
        if (console == null) {
            System.out.println("System.console() return null.");
            System.out.println("If you are trying to run from within your IDE, use the command line instead.");
            return;
        }
        System.out.println("Enter some characters...");
        String userInput = console.readLine();
        System.out.println("User input:  " + userInput + " [String length: " + userInput.length() + ", chars: " + userInput.toCharArray().length + ", bytes: " + userInput.getBytes(StandardCharsets.UTF_8).length + "]");
        System.out.println("codepoints:  " + userInput.codePoints().boxed().map(n -> "x" + Integer.toHexString(n) + " (" + n + ")").collect(Collectors.toList()).toString());
        System.out.println("UTF-8 bytes: " + getBytesList(userInput));
    }

    static String getBytesList(String userInput) throws UnsupportedEncodingException {
        StringBuilder byteList = new StringBuilder("[");
        for (int i = 0; i < userInput.length(); i++) {
            byte[] bytes = userInput.substring(i, i + 1).getBytes(StandardCharsets.UTF_8);
            for (int j = 0; j < bytes.length; j++) {
                byteList.append(Character.forDigit((bytes[j] >> 4) & 0xF, 16))
                        .append(Character.forDigit((bytes[j] & 0xF), 16));
                if (j < bytes.length - 1) {
                    byteList.append(" ");
                }
            }
            if (i < userInput.length() - 1) {
                byteList.append(", ");
            }
        }
        byteList.append("]");
        return byteList.toString();
    }
}

【讨论】:

  • 感谢您的回答。不幸的是,不支持 Netbeans 不是一种选择。这将在一年级的课堂上使用,学生们通过查看他们的 IDE 中的控制台已经很挣扎了。我不敢强迫他们每次需要运行程序时都使用 CMD。
  • @nerestaren 好的,我再看看。我认为更新您的问题可能会有所帮助,以明确要求“从命令行读取字符,没有任何特殊情况” 必须在 NetBeans 内完成。 (我不清楚。)
猜你喜欢
  • 2023-04-05
  • 1970-01-01
  • 2012-08-24
  • 1970-01-01
  • 1970-01-01
  • 2012-09-30
  • 2011-02-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多