Кодировка символов по умолчанию для вывода на консоль Java

2

Как Java определяет кодировку, используемую для System.out?

Учитывая следующий класс:

import java.io.File;
import java.io.PrintWriter;

public class Foo
{
    public static void main(String[] args) throws Exception
    {
        String s = "xxäñxx";
        System.out.println(s);
        PrintWriter out = new PrintWriter(new File("test.txt"), "UTF-8");
        out.println(s);
        out.close();
    }
}

Он сохраняется как UTF-8 и скомпилирован с javac -encoding UTF-8 Foo.java в системе Windows.

Затем на консоли git - bash (с использованием кодировки UTF-8) я:

$ java Foo
xxõ±xx
$ java -Dfile.encoding=UTF-8 Foo
xxäñxx
$ cat test.txt
xxäñxx
$ java Foo | cat
xxäñxx
$ java -Dfile.encoding=UTF-8 Foo | cat
xxäñxx

Что здесь происходит?

Очевидно, что java проверяет, подключен ли он к терминалу и в этом случае меняет свою кодировку. Есть ли способ заставить Java просто выводить простой UTF-8?


Я тоже пробовал с консолью cmd. Перенаправление STDOUT, похоже, не имеет никакого значения. Без параметра file.encoding он выдает ansi-кодировку с параметром, который выводит кодировку utf8.

  • 0
    System.out кодирует байты, используя кодировку по умолчанию . Иногда это даже кодировка, используемая консолью.
  • 0
    Но почему java Foo выводит что-то отличное от java Foo|cat ? - Кодировка по умолчанию должна быть такой же.
Показать ещё 1 комментарий
Теги:
console
character-encoding
utf-8

1 ответ

7
Лучший ответ

Я предполагаю, что ваша консоль все еще работает под cmd.exe. Я сомневаюсь, что ваша консоль действительно ожидает UTF-8 - я ожидаю, что это действительно OEM-кодировка DOS (например, 850 или 437.)

Java будет кодировать байты с использованием кодировки по умолчанию, установленной во время инициализации JVM.

Воспроизведение на моем ПК:

java Foo

Java кодируется как windows-1252; консоль декодируется как IBM850. Результат: Mojibake

java -Dfile.encoding=UTF-8 Foo

Java кодируется как UTF-8; консоль декодируется как IBM850. Результат: Mojibake

cat test.txt

cat декодирует файл как UTF-8; cat кодируется как IBM850; консоль декодируется как IBM850.

java Foo | cat

Java кодируется как windows-1252; cat декодируется как windows-1252; cat кодируется как IBM850; консоль декодирует как IBM850

java -Dfile.encoding=UTF-8 Foo | cat

Java кодируется как UTF-8; cat декодирует как UTF-8; cat кодируется как IBM850; консоль декодирует как IBM850

Эта реализация cat должна использовать эвристику, чтобы определить, являются ли символьные данные UTF-8 или нет, затем перекодирует данные из UTF-8 или ANSI (например, windows-1252) в консольную кодировку (например, IBM850.)

Это можно подтвердить с помощью следующих команд:

$ java HexDump utf8.txt
78 78 c3 a4 c3 b1 78 78

$ cat utf8.txt
xxäñxx

$ java HexDump ansi.txt
78 78 e4 f1 78 78

$ cat ansi.txt
xxäñxx

Команда cat может выполнить это определение, потому что e4 f1 не является допустимой последовательностью UTF-8.

Вы можете исправить выход Java:

HexDump - это тривиальное приложение Java:

import java.io.*;
class HexDump {
  public static void main(String[] args) throws IOException {
    try (InputStream in = new FileInputStream(args[0])) {
      int r;
      while((r = in.read()) != -1) {
        System.out.format("%02x ", 0xFF & r);
      }
      System.out.println();
    }
  }
}
  • 0
    Большое спасибо! Я был уверен, что cat просто копирует байты такими, какие они есть. Очевидно, что он действительно пытается «исправить» кодировку при записи в терминал. Я также не знал, что git-bash действительно использует терминал IBM850 cmd. Этот ответ был действительно полезным.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню