JAVA判斷輸入流字符編碼的困惑

近日在開發爬蟲程序時發現,如果事先不指定正確的字符集編碼,在得到InputStream字節流實例後使用程序自身去判斷,相關代碼如下
Java代碼
if(charset == null || "".equals(charset)) {   
     reader = new InputStreamReader(inputStream);   
     charset = reader.getEncoding();   
}else {   
     reader = new InputStreamReader(inputStream, charset);   
}         

在if塊語句中,往往會得到錯誤的charset,原因是創建了一個使用系統平臺字符集的 InputStreamReader實例,同時很多專業網站在製作時使用了一個小技巧,就是在文件開頭敲空格等,這樣就會造成JDK的相關類在判斷抓取到的輸入流是什麼編碼出現錯誤,繼而抓取下來的都是包含亂碼的網頁。例如抓取http://www.chinahr.com首頁代碼,根據if中的程序判斷,charset=”UTF8”,而頁面實際設置了charset=”gb2312”。從這裏也可看出JDK在底層的字節流,字符流的實現上仍然是不夠成熟,容易出現錯誤。
因爲在構成InputStreamReader實例時的字符集出錯,所以即使對抓取到的亂碼的網頁字符串重新轉碼也得不到正確的結果。
由於inputStream字節流只允許讀取一遍,往往還不支持mark(int),reset()等方法,所以根據這個特性,思考了若干解決方案,其中比較接近的一個是,先使用缺省字符集將字節流inputStream轉換爲字符流InputStreamReader,再使用BufferedReader類包裝一層,在BufferedReader讀取到包含charset的時候,對charset進行判斷後,重新實例化InputStreamReader,然後接着逐行讀取。代碼如下:
//原始的BufferedReader實例,reader即爲上面代碼產生的實例   
bufferedReader = new BufferedReader(reader);   
boolean mark = false;   
           
StringBuffer   buffer = new StringBuffer();   
String str = "";   
int count = 0;   
while ((str = bufferedReader.readLine()) != null) {   
    if(mark && count > 0) {   
         bufferedReader.reset();   
         count = 0;   
     }                  
               
     buffer.append(str).append("/n");   
               
    if(!mark){   
         count ++;   
         String tempStr = str.toLowerCase();   
        if(tempStr.indexOf(DetectorConstants.HtmlTagProperty.HTTP_EQUIV) != -1   
         && tempStr.indexOf(DetectorConstants.HtmlTagProperty.CHARSET) != -1){   
            //此處略過了實際分析過程,直接給出結果   
             String anotherCharset = "gb2312";   
            if(anotherCharset != null && !"".equals(anotherCharset) && !anotherCharset.equals(charset)){   
                 charset = anotherCharset;                          
                 reader = new InputStreamReader(urlStream, anotherCharset);   
                 bufferedReader = new BufferedReader(reader);   
                           
                int av = urlStream.available();   
                 bufferedReader.mark(av + 1);//也可以使用count試試   
                 mark = true;   
             }   
         }                  
     }   
}  

這種方法可以得到正確的編碼格式的page頁面,然而由於使用不同的字符集實例化InputStreamReader,造成inputStream流在使用新的字符集重新實例化後,之前的定位發生變化,前後的位置不一致,中間往往會漏掉大約400多行字符。
研究了一些相關開源項目,例如HtmlParser,發現也是無法提供一個正確的,好用的方法來判斷字節流的編碼格式。
來源:http://hi.baidu.com/%D0%A1%C2%EC%D2%CF_google/blog/item/14b41255e5ae9c55d00906e2.html

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/biexf/archive/2010/10/21/5957049.aspx

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章