Java 控制台中文问题(windows平台)
测试代码
import java.io.Console;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
public class JsTest {
@SuppressWarnings("rawtypes")
private static void outputCharset(){
Constructor[] ctors = Console.class.getDeclaredConstructors();
Constructor ctor = null;
for (int i = 0; i < ctors.length; i++) {
ctor = ctors[i];
if (ctor.getGenericParameterTypes().length == 0)
break;
}
try {
ctor.setAccessible(true);
Console c = (Console) ctor.newInstance();
Field f = c.getClass().getDeclaredField("cs");
f.setAccessible(true);
System.out.println(String.format("Console charset:%s",
f.get(c)));
System.out.println(String.format("Charset.defaultCharset():%s",
Charset.defaultCharset()));
} catch (Exception x) {
x.printStackTrace();
}
}
public static void main(String[] args) {
outputCharset();
System.out.println("中文");
}
}
编码
有两个编码需要提及的是:
1. Console charset(控制台编码)
我的是英文的Windows XP加上了中文支持。(在控制面板的Region中设置)
2. System default Charset(系统默认编码)
这个是系统默认编码,windows英文操作系统是cp1252(iso-8859-1)
试验
编译:
javac -encoding utf8 JsTest.java
因为我的源代码用utf8存贮,所以编译的时候加上了utf8选项。
测试1:
java zzz.JsTest
Java把字符串直接通过default Charset[windows-1252(iso-8859-1)]转化后输出到控制台,但是这个控制台只能识别code936(gb2312)的编码,所以不能识别,
输出??
指定file.encoding来改变default charset为gb2312,这下okay了
java -Dfile.encoding=gb2312 zzz.JsTest
测试3:
换成utf8看看,变成乱码。
Java -Dfile.encoding=utf8 zzz.JsTest
测试4:
通过chcp来改变控制台编码,行不通。
结论
1. 只有console charset 和 system default charset保持一致才不会乱码
2. chcp 65001(utf8)不能正常工作
3. 可以通过-Dfile.encoding改变default charset
解决方案
因为我们无法控制console的编码,如何能确保程序总是能正确输出,即使程序被放在日文OS上执行?
native unicode output
这种方案使用Windows Native API WriteConsoleW来输出,这样总是以unicode输出。(使用了JNA)
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.StdCallLibrary;
/** For unicode output on windows platform
* @author Sandy_Yin
*
*/
public class Console {
private static Kernel32 INSTANCE = null;
public interface Kernel32 extends StdCallLibrary {
public Pointer GetStdHandle(int nStdHandle);
public boolean WriteConsoleW(Pointer hConsoleOutput, char[] lpBuffer,
int nNumberOfCharsToWrite,
IntByReference lpNumberOfCharsWritten, Pointer lpReserved);
}
static {
String os = System.getProperty("os.name").toLowerCase();
if (os.startsWith("win")) {
INSTANCE = (Kernel32) Native
.loadLibrary("kernel32", Kernel32.class);
}
}
public static void println(String message) {
boolean successful = false;
if (INSTANCE != null) {
Pointer handle = INSTANCE.GetStdHandle(-11);
char[] buffer = message.toCharArray();
IntByReference lpNumberOfCharsWritten = new IntByReference();
successful = INSTANCE.WriteConsoleW(handle, buffer, buffer.length,
lpNumberOfCharsWritten, null);
if(successful){
System.out.println();
}
}
if (!successful) {
System.out.println(message);
}
}
}
原文:http://www.blogjava.net/sandy/archive/2012/01/19/368747.html
本文出自 传播、沟通、分享,转载时请注明出处及相应链接。
本文永久链接: https://www.nickdd.cn/?p=1859