我們的專案中會包含有很多檔案,但是可能我們沒有注意到的,我們的檔案的編碼不一定是utf-8,所以可能在別人電腦執行時出現亂碼。最近在做乙個專案,這個專案可以把我們的資料夾裡的所有文字,判斷他們是什麼編碼,如果不是使用者規定的編碼,那麼就告訴使用者,是否要把它規範為設定的編碼。
我們常用的編碼有 utf-8 和 gbk ,所以這就是我們的重點關注編碼,可惜現在沒有乙個好的辦法區別 utf-8 和 gbk 。
如果是帶 bom 的檔案,帶 bom 就是帶簽名,我們可以看到在 visualstudio 的 檔案-高階儲存 有 utf-8 帶簽名和 utf-8 編碼。
那麼帶簽名的意思是什麼,這個和歷史有關,我們做出了太多編碼,有時無法解析檔案的編碼,如我們在記事本寫上聯通,再次開啟會是亂碼的原因一樣,為了讓檔案自己告訴是什麼編碼,我們就取檔案的前四個 byte ,用於讓檔案說出自己的編碼。
對帶簽名檔案,我們可以簡單得到他的編碼。see:
private
static encoding autoencoding(byte bom)
// analyze the bom
if (bom[0] == 0x2b && bom[1] == 0x2f && bom[2] == 0x76)
return encoding.utf7; //85 116 102 55 //utf7 aa 97 97 0 0
//utf7 編碼 = 43 102 120 90
if (bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf)
return encoding.utf8; //無簽名 117 116 102 56
// 130 151 160 231
if (bom[0] == 0xff && bom[1] == 0xfe)
return encoding.unicode; //utf-16le
if (bom[0] == 0xfe && bom[1] == 0xff)
return encoding.bigendianunicode; //utf-16be
if (bom[0] == 0 && bom[1] == 0 && bom[2] == 0xfe && bom[3] == 0xff) return encoding.utf32;
return encoding.ascii; //如果返回ascii可能是gbk、無簽名 utf8
}
那麼對於沒有帶簽名的檔案,我們如何判斷?其實我找了現在很多大神的部落格,他們都認為這個是沒有乙個可行的方法,精確判斷。所以我們只能通過乙個近似的方法來判斷。
找了很久,發現了乙個很好的演算法,對於檔案長度不是3的倍數,和包含有中文、ascii字元的 gbk 編碼檔案,幾乎不會與utf8混淆。
我們統計屬於 gbk 的 byte 個數和屬於utf8的byte個數,比較兩個個數,如果countgbk 大於 countutf8 那麼編碼就是 gbk,否則是 utf8。如果相同,gg,所以我們需要乙個置信度變數。
看起來我們需要好多變數,於是寫乙個類
using system.io;
using system.text;
namespace encodingnormalior.model
////// 編碼
///public encoding encoding
////// 置信度
/// 範圍0-1,1表示確定,0表示不確定,注意:ascii編碼的置信度為0
///public
double confidencecount = 0;}}
那麼如何統計檔案中屬於 gbk的 byte 個數
我們需要知道 gbk 的編碼,對於一般的 ascii 字元,使用乙個 byte 和ascii一樣,如果乙個檔案都是 ascii 字元,那麼gbk 編碼和 ascii 的都一樣,我們統計得到屬於 gbk的byte個數為0。對於其他的字元,使用兩個 byte 表示。
我找到了乙個大神寫的判斷,
實際上試過了,不如使用firstbyte >= 161 && firstbyte <= 247 && secondbyte >= 161 && secondbyte <= 254
判斷。
那麼知道了如何判斷乙個字元是屬於gbk,那麼我們可以開始寫函式countgbk
///
/// 統計檔案屬於 gbk 的 byte數
//////
private
intcountgbk()
var length = countbuffer.length; //總長度
var buffer = countbuffer;
const
char head = (char) 0x80; //小於127 通過 &head==0
for (var i = 0; i < length; i++)
if (i + 1 >= length) //如果是大於127,需要兩字元,如果只有乙個,那麼檔案錯了,但是我也沒法做什麼
var secondbyte = buffer[i + 1]; //如果是gbk,那麼新增gbk byte 2
if (firstbyte >= 161 && firstbyte <= 247 &&
secondbyte >= 161 && secondbyte <= 254)
}return count;
}
統計檔案中屬於 utf8 的byte個數
///
/// 屬於 utf8 的 byte 數
//////
private
intcountutf8()
var length = countbuffer.length;
var buffer = countbuffer; // new byte[length];
const
char head = (char) 0x80;
//while ((n = stream.read(buffer, 0, n)) > 0)
var temphead = head;
var wordlength = 0; //單詞長度,乙個字使用多少個byte
while ((temp & temphead) != 0) //存在多少個byte
if (wordlength <= 1)
wordlength--; //去掉最後乙個,可以讓後面的 point大於wordlength
if (wordlength + i >= length)
var point = 1; //utf8的這個word 是多少 byte
//utf8在兩位元組和三位元組的編碼,除了最後乙個 byte
//其他byte 大於127
//所以 除了最後乙個byte,其他的byte &head >0
for (; point <= wordlength; point++)
}if (point > wordlength)}}
return count;
}
我們判斷如果是不帶簽名的檔案,判斷為 utf8 或gbk,可以使用判斷屬於 gbk 的 byte 多還是 utf8 多。
var countutf8 = countutf8();
if (countutf8 == 0)
else
else
}
下面是我看到的大神的部落格,如果希望了解編碼的問題,可以參見下面的部落格。
我把專案開源,希望能幫到大家。
聽說專案的名字拼錯了,大家不要笑。
參見:文章還發在 他會更新比較快,如果遇到任何的問題,歡迎交流
C語言判斷檔案編碼格式
功能 實現檔案編碼格式的判斷 通過乙個檔案的最前面三個位元組,可以判斷出該的編碼型別 ansi 無格式定義 第乙個位元組開始就是檔案內容 unicode 前兩個位元組為fffe unicode big endian 前兩位元組為feff utf 8 前兩位元組為efbb,第三位元組為bf inclu...
C語言判斷檔案編碼格式
功能 實現檔案編碼格式的判斷 通過乙個檔案的最前面三個位元組,可以判斷出該的編碼型別 ansi 無格式定義 第乙個位元組開始就是檔案內容 unicode 前兩個位元組為fffe unicode big endian 前兩位元組為feff utf 8 前兩位元組為efbb,第三位元組為bf inclu...
C 判斷txt檔案編碼格式
獲取檔案的編碼格式 public class encodingtype 通過給定的檔案流,判斷檔案的編碼型別 檔案流 檔案的編碼型別 public static system.text.encoding gettype filestream fs byte unicodebig new byte b...