C 判斷檔案編碼

2022-01-15 15:17:17 字數 3852 閱讀 8124

我們的專案中會包含有很多檔案,但是可能我們沒有注意到的,我們的檔案的編碼不一定是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...