java控制台输出的默认字符编码

mic*_*has 5 java windows console utf-8 character-encoding

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

它保存为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
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?

很明显,java会检查它是否连接到终端,并在这种情况下改变其编码.有没有办法强制Java只输出普通的UTF-8?


我也尝试使用cmd控制台.重定向STDOUT似乎没有任何区别.如果没有file.encoding参数,它会输出带有参数的ansi编码,并输出utf8编码.

McD*_*ell 9

我假设您的控制台仍在cmd.exe下运行.我怀疑你的控制台真的期待UTF-8 - 我希望它真的是OEM DOS编码(例如850或437).

Java将在JVM初始化期间使用默认编码集对字节进行编码.

在我的电脑上再现:

java Foo
Run Code Online (Sandbox Code Playgroud)

Java编码为windows-1252; 控制台解码为IBM850.结果:Mojibake

java -Dfile.encoding=UTF-8 Foo
Run Code Online (Sandbox Code Playgroud)

Java编码为UTF-8; 控制台解码为IBM850.结果:Mojibake

cat test.txt
Run Code Online (Sandbox Code Playgroud)

cat将文件解码为UTF-8; cat编码为IBM850; 控制台解码为IBM850.

java Foo | cat
Run Code Online (Sandbox Code Playgroud)

Java编码为windows-1252; 猫解码为windows-1252; cat编码为IBM850; 控制台解码为IBM850

java -Dfile.encoding=UTF-8 Foo | cat
Run Code Online (Sandbox Code Playgroud)

Java编码为UTF-8; 猫解码为UTF-8; cat编码为IBM850; 控制台解码为IBM850

的此实现必须使用试探法来确定,如果字符数据是UTF-8或不是,则转码从任UTF-8或ANSI到控制台编码数据(例如,窗口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
Run Code Online (Sandbox Code Playgroud)

命令可以做出此决定,因为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();
    }
  }
}
Run Code Online (Sandbox Code Playgroud)