Posted on 2012-01-19 16:18
小明 閱讀(3717)
評論(1) 編輯 收藏 所屬分類:
開發(fā)日志
測試代碼 1 import java.io.Console;
2 import java.lang.reflect.Constructor;
3 import java.lang.reflect.Field;
4 import java.nio.charset.Charset;
5
6 public class JsTest {
7
8 @SuppressWarnings("rawtypes")
9 private static void outputCharset(){
10 Constructor[] ctors = Console.class.getDeclaredConstructors();
11 Constructor ctor = null;
12 for (int i = 0; i < ctors.length; i++) {
13 ctor = ctors[i];
14 if (ctor.getGenericParameterTypes().length == 0)
15 break;
16 }
17 try {
18 ctor.setAccessible(true);
19 Console c = (Console) ctor.newInstance();
20 Field f = c.getClass().getDeclaredField("cs");
21 f.setAccessible(true);
22 System.out.println(String.format("Console charset:%s",
23 f.get(c)));
24 System.out.println(String.format("Charset.defaultCharset():%s",
25 Charset.defaultCharset()));
26 } catch (Exception x) {
27 x.printStackTrace();
28 }
29 }
30
31 public static void main(String[] args) {
32 outputCharset();
33 System.out.println("1234中文5678");
34 }
35 }
編碼有兩個編碼需要提及的是:
1. Console charset(控制臺編碼)
控制臺編碼是windows的命令行窗口的編碼,可以使用chcp來查看,也可以是窗口屬性中看到。
我的是英文的Windows XP加上了中文支持。(在控制面板的Region中設置)

2. System default Charset(系統(tǒng)默認編碼)
這個是系統(tǒng)默認編碼,windows英文操作系統(tǒng)是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)的編碼,所以不能識別,
輸出??
測試2:
指定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上執(zhí)行?
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);
}
}
}