2010-08-04 51 views
13

嗯,我需要找出我在某些目錄中找到的哪些文件是UTF8編碼ANSI編碼,以便在稍後決定的其他內容中更改編碼。我的問題是..我怎麼才能找出如果一個文件是UTF8或ANSI編碼?這兩種編碼實際上都在我的文件中。如何找出文件的編碼? C#

回答

12

沒有可靠的辦法做到這一點(因爲該文件可能只是隨機二進制文件),但是由Windows記事本軟件完成的過程詳見Micheal S Kaplan的博客:

http://www.siao2.com/2007/04/22/2239345.aspx

  1. 檢查前兩個字節; 1.如果存在UTF-16 LE BOM,則將其作爲「Unicode」文件處理(並加載它); 2.如果存在UTF-16 BE BOM,則將其作爲「Unicode(Big Endian)」文件處理(並加載它); 3.如果前兩個字節看起來像UTF-8 BOM的開始部分,那麼檢查下一個字節,如果我們有UTF-8 BOM,則將其作爲「UTF-8」文件處理(並加載它) ;
  2. 與IsTextUnicode一起檢查該函數是否認爲它是無BOM的UTF-16 LE,如果是,則將其作爲「Unicode」文件對待(並加載它);
  3. 使用1998年的原始RFC 2279定義檢查它是否使用UTF-8,然後將它作爲「UTF-8」文件處理(並加載它);
  4. 假設使用機器的默認系統代碼頁的ANSI文件。

現在請注意,有一些孔 這裏,喜歡的事實,第二步還 不會做的相當好與BOM少 UTF-16(甚至有可能是一個錯誤 這裏,我m不知道 - 如果是這樣的話,它是記事本中的一個錯誤 ,它不包括 IsTextUnicode中的任何錯誤)。

+7

如果您爲'detectEncodingFromByteOrderMarks'參數傳遞'true',StreamReader會自動執行此操作。 http://msdn.microsoft.com/en-us/library/7bc2hwcb.aspx – dtb 2010-08-04 09:35:05

+0

謝謝,我不知道.NET有這個程序的內部支持! – sukru 2010-08-04 09:36:57

+0

在我的測試中,'detectEncodingFromByteOrderMarks'標誌沒有檢測到ANSI編碼 – Bertvan 2013-03-21 11:20:10

4

http://msdn.microsoft.com/en-us/netframework/aa569610.aspx#Question2

還有就是檢測 任意ANSI代碼頁中沒有很好的方法,雖然有 了一些嘗試做基於某些 字節序列的中間的概率這 的文字。 我們不嘗試在StreamReader中。一個 幾個文件格式,如XML或HTML有 指定字符的方式設置 在文件中的第一行,這樣的Web瀏覽器 ,數據庫和像 XmlTextReader的類可以正確讀取這些文件 。但是,許多文本文件不 有這種類型的信息在建 。

1

的Unicode/UTF8/UnicodeBigEndian被認爲是不同的類型。 ANSI被認爲與UTF8相同。

public class EncodingType 
{ 
    public static System.Text.Encoding GetType(string FILE_NAME) 
    { 
     FileStream fs = new FileStream(FILE_NAME, FileMode.Open, FileAccess.Read); 
     Encoding r = GetType(fs); 
     fs.Close(); 
     return r; 
    } 

    public static System.Text.Encoding GetType(FileStream fs) 
    { 
     byte[] Unicode = new byte[] { 0xFF, 0xFE, 0x41 }; 
     byte[] UnicodeBIG = new byte[] { 0xFE, 0xFF, 0x00 }; 
     byte[] UTF8 = new byte[] { 0xEF, 0xBB, 0xBF }; //with BOM 
     Encoding reVal = Encoding.Default; 

     BinaryReader r = new BinaryReader(fs, System.Text.Encoding.Default); 
     int i; 
     int.TryParse(fs.Length.ToString(), out i); 
     byte[] ss = r.ReadBytes(i); 
     if (IsUTF8Bytes(ss) || (ss[0] == 0xEF && ss[1] == 0xBB && ss[2] == 0xBF)) 
     { 
      reVal = Encoding.UTF8; 
     } 
     else if (ss[0] == 0xFE && ss[1] == 0xFF && ss[2] == 0x00) 
     { 
      reVal = Encoding.BigEndianUnicode; 
     } 
     else if (ss[0] == 0xFF && ss[1] == 0xFE && ss[2] == 0x41) 
     { 
      reVal = Encoding.Unicode; 
     } 
     r.Close(); 
     return reVal; 

    } 

    private static bool IsUTF8Bytes(byte[] data) 
    { 
     int charByteCounter = 1;  
     byte curByte; 
     for (int i = 0; i < data.Length; i++) 
     { 
      curByte = data[i]; 
      if (charByteCounter == 1) 
      { 
       if (curByte >= 0x80) 
       { 
        while (((curByte <<= 1) & 0x80) != 0) 
        { 
         charByteCounter++; 
        } 
          
        if (charByteCounter == 1 || charByteCounter > 6) 
        { 
         return false; 
        } 
       } 
      } 
      else 
      { 
       if ((curByte & 0xC0) != 0x80) 
       { 
        return false; 
       } 
       charByteCounter--; 
      } 
     } 
     if (charByteCounter > 1) 
     { 
      throw new Exception("Error byte format"); 
     } 
     return true; 
    } 

} 
+0

這看起來像一大堆代碼。但是,不是UTF16 LE和UTF16-BE應該分別具有簽名「FF FE」和「FE FF」嗎?你已經添加了一個額外的字節。請參閱:http://www.unicode.org/faq/utf_bom.html#bom4 – 2012-10-12 00:14:54

+0

順便說一句,您的IsUTF8Bytes()函數與Christoph的答案相比如何顯示:http://stackoverflow.com/a/1031773/ 848344 – 2012-10-12 01:49:15

+0

@DanW:我不知道Christoph的回答來自哪裏,我發佈的代碼是我工作過的項目的一部分,由一個隊友編寫。 – 2012-10-12 02:18:51