問題來源:
在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編碼的文檔時均可成功讀取,大家放心使用