小明思考

          Just a software engineer
          posts - 124, comments - 36, trackbacks - 0, articles - 0
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          Java 控制臺中文問題(windows平臺)

          Posted on 2012-01-19 16:18 小明 閱讀(3720) 評論(1)  編輯  收藏 所屬分類: 開發日志
          測試代碼

           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(系統默認編碼)
          這個是系統默認編碼,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)的編碼,所以不能識別,
          輸出??

          測試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上執行?

          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);
                  }
              }
          }



          評論

          # re: Java 控制臺中文問題(windows平臺)  回復  更多評論   

          2012-01-23 23:13 by tb
          很好啊
          主站蜘蛛池模板: 苏尼特左旗| 五华县| 长宁区| 格尔木市| 乐平市| 郧西县| 高要市| 上饶县| 锡林郭勒盟| 葫芦岛市| 凤山县| 岗巴县| 凉城县| 百色市| 会宁县| 开封县| 澄迈县| 福州市| 衡南县| 灌阳县| 和政县| 北碚区| 青阳县| 金平| 南雄市| 云南省| 慈溪市| 通河县| 阿荣旗| 仲巴县| 奈曼旗| 石阡县| 肇源县| 赤水市| 宣化县| 青冈县| 凭祥市| 庆阳市| 澳门| 南开区| 客服|