C++判斷文件編碼類型(省去你不必要的麻煩!)

問題來源:

在c++ primier plus第六版的第十七章設計文件操作的習題中,我用記事本創建了一個包含中文的文件,通過傳統的ifstream去讀取的時候,中文部分出現了亂碼,發現是字符編碼的問題。

問題相關描述:

用上述直接創建方式生成的txt是utf-8,但是如果我們在程序內部通過ofstream去創建文件的話,文件編碼是ANSI,這時候通過ifstream讀取並不會出錯。

判斷文件編碼

參考https://blog.csdn.net/bladeandmaster88/article/details/54767557
這裏我對他的代碼進行了修改,因爲直接在我的電腦上結果不對

#include <fstream>
using namespace std;
 
int main()
{
    ifstream fin("C:/Users/Administrator/Desktop/w/1.cpp",ios::binary);
    unsigned char  s2;
    fin.read((char*)&s2, sizeof(s2));//讀取第一個字節,然後左移8位
    int p = s2<<8;
    fin.read((char*)&s2, sizeof(s2));//讀取第二個字節
    p +=s2;
 
    string code;
 
    switch(p)//判斷文本前兩個字節
    {
    case 0xfffe:  //65534
        code = "Unicode";    
        break;
    case 0xfeff://65279
        code = "Unicode big endian";
        break;
    case 0xe6a2://59042
        code = "UTF-8";     
        break;
 default: 
        code = "ANSI"; 
     }
     fin.close(); 
     return 0;
}

經過測試,我這裏UTF-8輸出的p是59042經過轉換是0xe6a2,這裏大家可以再進行一下測試

讀取UTF-8文件

這裏對文件的要求是,直接創建txt文檔,然後在裏面輸入中文,先上代碼然後再進行說明

#include<iostream>
#include<fstream>
#include<string>
#include<codecvt>
#include<locale>
using namespace std;


int main(int argc, char *argv[])
{
	ifstream fin("chapter17_4.txt");
    ofstream fout("chapter17_4.3.txt");
    std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
    string strfile;
    if (!fin.is_open())
    {
        cerr << "error in open file.\n";
        return 1;
    }
    unsigned char s2;
    fin.read((char*)&s2, sizeof(s2));//讀取第一個字節,然後左移8位
    unsigned int p = s2 << 8;
    fin.read((char*)&s2, sizeof(s2));//讀取第二個字節
    p += s2;
    cout << p << endl;
    string code;
    switch (p)//判斷文本前兩個字節
    {
    case 0xfffe:  //65534
        code = "Unicode";
        break;
    case 0xfeff://65279
        code = "Unicode big endian";
        break;
    case 0xe6a2://59042
    {   
        code = "utf-8";
        fin.seekg(0);
        while (getline(fin, strfile) && strfile.size() > 0)
        {
            //cout << strfile << endl;
            wstring wb = conv.from_bytes(strfile);//轉爲寬字符
            wcout.imbue(locale("chs"));			//更改區域設置 只爲控制檯輸出顯示
            wcout << wb << endl;
        }
        fin.close();
        break;
    }    
    default:
        code = "ANSI";
        {
            while (getline(fin, strfile) && strfile.size() > 0)
            {
                cout << strfile << endl;
            }
        }
    }
    cout << "編碼是:" << code;
	cout << "\nDone.\n";
	system("pause");
	return 0;
}

其中的寬字符和普通字符轉換的部分我是參考https://blog.csdn.net/x_iya/article/details/14500435然後自己閱讀了一下官方msdn文檔

結論

上面這段代碼參考了網上的很多資料,其中讀取UTF-8這段是找到了比較簡潔的一種方法,是用到了c++11的新特性,這裏還存在一些問題,就是對於to_bytes()方法的使用好像還存在着一些問題,等解決了再回來填坑。
上面這段代碼可以改成一個接口,用來判斷文件編碼,然後使用不同的方法進行讀取,這裏只是檢測了幾種編碼,然後如果大家要檢測UTF-8 BOM,應對0xefbb進行匹配。
這點東西研究了好久纔算是讓自己滿意的解決了,學到了關於寬字符的一些處理方式,然後最文件的基本操作更熟練了,希望能幫到有需要的人
經過測試上述代碼在讀取utf-8以及ANSI編碼的文檔時均可成功讀取,大家放心使用

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