<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    失樂(lè)園

    技術(shù)之路

    BlogJava 聯(lián)系 聚合 管理
      19 Posts :: 44 Stories :: 40 Comments :: 0 Trackbacks
           大多數(shù)文本編輯器在打開(kāi)文件時(shí)都能夠自動(dòng)檢測(cè)文件的編碼,那它是怎樣做到的?我雖然沒(méi)有實(shí)現(xiàn)過(guò)一個(gè)文本編輯器,但是可以猜測(cè)的是,它有一個(gè)默認(rèn)的編碼集合,然后嘗試用每一個(gè)編碼去解碼打開(kāi)的文件,如果能夠解碼則表示這就是文件的正確編碼。有一些特殊情況,有些編碼在文件開(kāi)頭有特殊的標(biāo)記字節(jié),因而可以很快檢測(cè),這里不考慮。現(xiàn)在的核心問(wèn)題就是如何決定一個(gè)編碼是否能夠解碼一個(gè)文件,在Java1.4中可以利用nio中的Charset來(lái)解決這個(gè)問(wèn)題。
    /**
    * 測(cè)試輸入字節(jié)流是否能夠使用指定的字符集解碼。
    */
    public static boolean canDecode(InputStream input, Charset charset) throws IOException {  
        ReadableByteChannel channel = Channels.newChannel(input);  
        CharsetDecoder decoder = charset.newDecoder();  

        ByteBuffer byteBuffer = ByteBuffer.allocate(2048);  
        CharBuffer charBuffer = CharBuffer.allocate(1024);  

        boolean endOfInput = false;  
        while (!endOfInput) {  
            int n = channel.read(byteBuffer);  
            byteBuffer.flip(); // flip so it can be drained  
              
            endOfInput = (n == -1);  
            CoderResult coderResult = decoder.decode(byteBuffer, charBuffer, endOfInput);  
            charBuffer.clear();  
            if (coderResult == CoderResult.OVERFLOW) {  
                while (coderResult == CoderResult.OVERFLOW) {  
                    coderResult = decoder.decode(byteBuffer, charBuffer, endOfInput);  
                    charBuffer.clear();  
                }  
            }  
            if (coderResult.isError()) {  
                return false;  
            }  
            byteBuffer.compact(); // compact so it can be refilled  
        }  
        CoderResult coderResult;  
        while ((coderResult = decoder.flush(charBuffer)) == CoderResult.OVERFLOW) {  
            charBuffer.clear();  
        }  
        if (coderResult.isError()) {  
            return false;  
        }  
          
        return true;  
    }
    要理解上面的代碼必須熟悉對(duì)Buffer和Channel的操作以及解碼的過(guò)程。上面的代碼只是決定能不能解碼,下面代碼能夠解碼出的內(nèi)容寫(xiě)到字符輸出流中(也就是Writer),它要更復(fù)雜一些。
    Java代碼
    /**
    * 使用指定的字符集解碼字節(jié)輸入流,并將它寫(xiě)入到字符輸出流中,如果發(fā)生解碼錯(cuò)誤則返回false,否則返回true,
    * 輸入中的無(wú)效字節(jié)序列將被忽略。
    */
    public static boolean decode(InputStream input, Writer output, Charset charset) throws IOException {  
        ReadableByteChannel channel = Channels.newChannel(input);  
        CharsetDecoder decoder = charset.newDecoder();  

        ByteBuffer byteBuffer = ByteBuffer.allocate(2048);  
        CharBuffer charBuffer = CharBuffer.allocate(1024);  

        boolean endOfInput = false;  
        boolean error = false;  
        while (!endOfInput) {  
            int n = channel.read(byteBuffer);  
            byteBuffer.flip(); // flip so it can be drained  
              
            endOfInput = (n == -1);  
            CoderResult coderResult = decoder.decode(byteBuffer, charBuffer, endOfInput);  
            error = drainCharBuffer(error, byteBuffer, charBuffer, coderResult, output);  
            if (coderResult != CoderResult.UNDERFLOW) {  
                while (coderResult != CoderResult.UNDERFLOW) {  
                    coderResult = decoder.decode(byteBuffer, charBuffer, endOfInput);  
                    error = drainCharBuffer(error, byteBuffer, charBuffer, coderResult, output);  
                }  
            }  
            byteBuffer.compact(); // compact so it can be refilled  
        }  
        CoderResult coderResult;  
        while ((coderResult = decoder.flush(charBuffer)) != CoderResult.UNDERFLOW) {  
            error = drainCharBuffer(error, byteBuffer, charBuffer, coderResult, output);  
        }  
        error = drainCharBuffer(error, byteBuffer, charBuffer, coderResult, output);  
          
        output.flush();  
        return !error;  
    }  

    private static boolean drainCharBuffer(boolean error, ByteBuffer byteBuffer,   
            CharBuffer charBuffer, CoderResult coderResult, Writer output) throws IOException {  
        // write charBuffer to output  
        charBuffer.flip();  
        if (charBuffer.hasRemaining())  
            output.write(charBuffer.toString());  
        charBuffer.clear();  
          
        if (coderResult.isError()) {  
            error = true;  
            byteBuffer.position(byteBuffer.position() + coderResult.length()); // ignore invalid byte sequence  
        }  
        return error;  
    }

    要注意byteBuffer的大小不能太小以至于比一個(gè)字符的最大字節(jié)數(shù)還要小,比如說(shuō)utf-8的每個(gè)字符最多可能占用4個(gè)字節(jié),如果設(shè)置byteBuffer的大小為3,解碼結(jié)果可能總是CoderResult.UNDERFLOW,但是又無(wú)法再往byteBuffer填充數(shù)據(jù),因而會(huì)出現(xiàn)死循環(huán)。

    另外要注意的是,程序可能得到錯(cuò)誤的結(jié)果,如:
    String s = "abc中國(guó)";  
    byte[] utf8Bytes = s.getBytes(Charset.forName("utf-8"));  
    byte[] gbkBytes = s.getBytes(Charset.forName("gbk"));  
    CharArrayWriter writer = new CharArrayWriter();  
    System.out.println(decode(new ByteArrayInputStream(utf8Bytes), writer, Charset.forName("utf-8")));  
    System.out.println(writer.toString());  
    writer = new CharArrayWriter();  
    System.out.println(decode(new ByteArrayInputStream(utf8Bytes), writer, Charset.forName("gbk")));  
    System.out.println(writer.toString());  

    輸出結(jié)果:
    Java代碼
    true
    abc中國(guó)  
    true
    abc涓 浗

    可以看到用utf-8編碼的字節(jié)流仍然可以用gbk進(jìn)行解碼,但是解碼的結(jié)果卻不對(duì)。這是偶然情況,將字符串換成"中國(guó)人",則用gbk就不能解碼了。
    posted on 2010-08-17 09:41 狄浩 閱讀(17390) 評(píng)論(0)  編輯  收藏

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 免费a级毛片无码a∨蜜芽试看 | 亚洲电影国产一区| eeuss草民免费| 免费人成在线观看网站视频| 日韩亚洲不卡在线视频中文字幕在线观看| 国产妇乱子伦视频免费| 亚洲无限乱码一二三四区| 在线观看永久免费| 久久精品国产亚洲av麻豆图片| 67194熟妇在线永久免费观看 | 亚洲gay片在线gv网站| 好男人视频在线观看免费看片| 亚洲成_人网站图片| 国产成人啪精品视频免费网| 国产亚洲精品欧洲在线观看| 亚洲av午夜成人片精品电影| 一级一级一级毛片免费毛片| 中文字幕中韩乱码亚洲大片| 男人天堂免费视频| 亚洲精品国产情侣av在线| 台湾一级毛片永久免费| 亚洲精品乱码久久久久久V| 国产精品无码一二区免费| 一区二区三区免费视频网站| 亚洲国产精品久久久天堂| 91精品国产免费久久国语蜜臀| 亚洲国产成人精品久久| 成人免费777777| 一区二区三区免费精品视频| 无码乱人伦一区二区亚洲| 97人妻无码一区二区精品免费| 国产偷国产偷亚洲高清人| 亚洲中文字幕无码一区| 中文字幕在线免费| 久久亚洲欧美国产精品| 亚洲精品成人网站在线观看| 亚洲香蕉免费有线视频| 亚洲AV永久无码精品一福利| 亚洲精品一品区二品区三品区| 天天影院成人免费观看| 免费国产在线精品一区|