2013-03-08 60 views
3

我需要檢查編碼類型的文件。如果它是可重複的,則返回true。
根據這SO answer我用Java代碼轉換了這個邏輯。但它不起作用。沒錯,這部分代碼:編碼檢測方法不起作用

if ((buffer[0] & 0xF8) == 0xF0) { 
     if (((buffer[1] & 0xC0) == 0x80) 
      && ((buffer[2] == 0x80) && ((buffer[3] == 0x80)))) 
      return true; 
    } else if ((buffer[0] & 0xF0) == 0xE0) { 
     if (((buffer[1] & 0xC0) == 0x80) && ((buffer[2] & 0xC0) == 0x80)) 
      return true; 
    } else if ((buffer[0] & 0xE0) == 0xC0) { 
     if (((buffer[1] & 0xC0) == 0x80)) 
      return true; 
    } return false; 

這個檢查不正確,此時檢查100%UTF-8代碼! =>結果是return false

所有部分的代碼:

class EncodindsCheck implements Checker { 
    private static final int UTF8_HEADER_SIZE = 8; 

    @Override 
    public boolean check(File currentFile) { 
     return isUTF8(currentFile); 
    } 

    public static boolean isUTF8(File file) { 
     // validate input 
     if (null == file) { 
      throw new IllegalArgumentException("input file can't be null"); 
     } 
     if (file.isDirectory()) { 
      throw new IllegalArgumentException(
        "input file refers to a directory"); 
     } 

     // read input file 
     byte[] buffer; 
     try { 
      buffer = readUTFHeaderBytes(file); 
     } catch (IOException e) { 
      throw new IllegalArgumentException(
        "Can't read input file, error = " + e.getLocalizedMessage()); 
     } 

     if ((buffer[0] & 0xF8) == 0xF0) { 
      if (((buffer[1] & 0xC0) == 0x80) 
       && ((buffer[2] == 0x80) && ((buffer[3] == 0x80)))) 
       return true; 
     } else if ((buffer[0] & 0xF0) == 0xE0) { 
      if (((buffer[1] & 0xC0) == 0x80) && ((buffer[2] & 0xC0) == 0x80)) 
       return true; 
     } else if ((buffer[0] & 0xE0) == 0xC0) { 
      if (((buffer[1] & 0xC0) == 0x80)) 
       return true; 
     } 

     return false; 
    } 

    private static byte[] readUTFHeaderBytes(File input) throws IOException { 
     byte[] buffer = new byte[UTF8_HEADER_SIZE]; 
     // read data 
     FileInputStream fis = new FileInputStream(input); 
     fis.read(buffer); 
     fis.close(); 
     return buffer; 
    } 
} 

問題:

  • 爲什麼沒有此檢查工作的?
  • 如何以這種方式解決檢查檢測問題(作爲UTF-8字符序列)?
  • 如何檢查其他字符集(UTF-16等)?
+0

你能否提供一個失敗的UTF-8文件樣本? – jazzbassrob 2013-03-08 14:56:59

+0

@jazzbassrob我該怎麼做? – 2013-03-08 15:02:27

+0

你讀過原來的答案嗎?是否緩衝區[0]甚至有一個字節> 0x7f? – Ingo 2013-03-08 15:06:27

回答

2

UTF-8中的代碼點長度可以是1,2,3或4個字節。

如果所有的編碼點都在U + 0000到U + 007F的範圍內,那麼isUTF8將返回錯誤。在這種情況下,該文件對於大量編碼(UTF-8,ASCII,ANSI編碼等)有效

您的UTF-8檢查相信運氣的第一個代碼點高於U + 007F。

我建議你看看a more comprehensive encoding detection API,至少作爲一個例子。


注意fis.read(buffer);不能保證填充陣列;類型合約要求您檢查讀取字節數的返回值。

+0

我該如何解決這個問題,並以有效的方式檢查文件?你介意我問,爲什麼我們要做'(buffer [0]&0xF8)'這個結果'== 0xF0' - 在這個例子中。爲什麼我們需要這個變體? – 2013-03-08 18:26:06

+0

'fis.read(buffer);' - 如何能夠規避這種不確定性? – 2013-03-09 09:24:46

+0

我沒有檢查過你的號碼,但是面具應該檢查[編碼方案](http://en.wikipedia.org/wiki/UTF-8#Description)。例如,如果第一個字節與「1110xxxx」匹配,那麼接下來的兩個字符必須匹配「10xxxxxx」。但是,你可以避免所有這些,並使用'Decoder'類型[檢查格式錯誤的輸入](http://docs.oracle.com/javase/7/docs/api/java/nio/charset/CharsetDecoder.html #onMalformedInput%28java.nio.charset.CodingErrorAction%29)。並不是說這將保證文件是UTF-8 - 只是數據不違反這些規則 - 沒有辦法可靠地檢測編碼。 – McDowell 2013-03-11 09:25:51