爲什麼Qt和很多軟件都會有亂碼問題
- 首先,字符串不管是存儲到文件還是內存裏面,它都只是字節而已,字符字形只是經過轉換顯示給人看的。同樣的字節,在不同的編碼下,就代表不同的字符。因此,程序寫入文件和讀取文件時,使用的編碼必須一致
- 代碼編輯器(IDE)在保存和編譯源代碼時,也是需要知道編碼方式的,如果代碼保存時使用的編碼,和編譯器讀取代碼時使用的編碼不一樣,也會出現亂碼問題。這個道理和上面其實是一樣的,編譯器本身也是一種程序,代碼就是它讀取的文件
- 編輯器顯示代碼和保存代碼時使用的編碼可能是不一致的。比如我們指定了IDE的編碼方式爲ASCII,是不支持中文的,但有可能我們仍然可以輸入漢字。因爲編譯器可能會用Unicode來顯示,然後保存的時候,以ASCII來存儲。當我們保存後再重啓IDE,文件就亂碼了。
- 代碼編輯器和代碼控制檯,也有可能使用的是不同的編碼。因爲代碼編輯器管理的是文件,代碼控制檯是和cmd進行通信,其實是兩種功能
- 切換編碼後,英文和數字不一定會亂碼。這是因爲英文字母和羅馬數字屬於國際通用字符,幾乎所有的編碼格式都包含這些字符,並且和ASCII使用一樣的編碼值。所以即便切換了編碼,它們有可能還是表示同樣的字符
- std::string是以char數組的形式來存儲字符的,一個字符佔一個字節,而漢字屬於寬字符,一個字符佔兩個字節,因此需要通過轉換才能正常打印顯示。QDebug和QString自動幫我們封裝實現了這些功能,用C++原生代碼轉換過於麻煩,建議用Qt現成的接口
- 關於不同編碼方式的區別,可以參考這篇博客:https://hellogoogle.blog.csdn.net/article/details/103455674
理想的文件讀寫方式
//打印源代碼字符串
//編譯器統一使用默認編碼,或IDE自動識別源文件編碼,無需指定
string str = "hello";
print(str);
//寫入文件
//指定字符編碼,或省略編碼參數,使用默認編碼
file.write(byte[] buffer, string encoding);
file.write(string text, string encoding);
//讀取文件
//指定字符編碼,或省略編碼參數,使用默認編碼
file.setEncoding(string encoding);
string line= file.readLine();
string text = file.readAll();
這是一個比較理想,也很容易理解的代碼形式。如果字符串可以這樣讀寫,string也可以直接打印,那真是太爽了
在很多Java代碼中,字符串的讀寫就是如此簡單。因爲代碼編輯器和開發框架,都默認使用了UTF8編碼,保證了一致性問題
如果不指定編碼,那麼所有地方默認使用的都是UTF8編碼,這樣在寫代碼時,甚至都可以省略編碼方式這個參數了
只不過很遺憾,C++畢竟是底層語言(低級語言),封裝程度較低,沒有一個正式易用的string類型,std::string本質上還是一個char數組,或者說是字節數組,沒有字符編碼信息。
在做Qt開發時,還是建議所有地方都使用Qt的QString,比較Qt對編碼功能進行了封裝,當然Qt沒有像某些Java框架那樣實現完全自動化,還需要我們自己去了解如何使用接口,不過比起原生C++代碼,已經算是極其方便了
Qt可以防止中文亂碼的一些編碼習慣
- 設置QtCreator代碼編輯器編碼爲UTF8
【Tools】-【Options】-【Text Editor】-【Behavior】-【Default Encoding】-【UTF-8】 - 告訴編譯器代碼文件的編碼方式。編譯器是不知道IDE代碼文件編碼方式的,在未明確指定IDE編碼方式的情況下,將使用編譯器默認的編碼方式,而MSVC編譯器和MinGW編譯器的默認編碼方式是不一樣,這樣就有可能出問題。在未明確指定編碼方式的情況下,最終代碼是否正確,既取決於文件編碼方式,又取決於編譯器默認編碼方式,就算允許正常,有可能只是偶然,換個編譯器可能就亂碼了
- 讀寫時設置文本流的編碼爲UTF8
- 打印文本時使用QDebug和QString
//指定源文件編碼方式
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("utf-8"));
//寫文本
QTextStream out(&file);
out.setCodec("utf-8");
out << QString("C++入門到放棄") << endl;
//讀文本
QTextStream in(&file);
QString text;
in.setCodec("utf-8");
in >> text >> endl;
//打印文本
qDebug() << QString("C++入門到放棄") << endl;
QTextCodec::setCodecForCStrings相當於全局設置,如果我們想不同的字符保存爲不同的編碼格式,也可以使用以下接口
//視str爲ASCII編碼
QString QString::fromAscii ( const char * str, int size = -1 )
//視str爲Latin1編碼
QString QString::fromLatin1 ( const char * str, int size = -1 )
//視str爲Utf8編碼
QString QString::fromUtf8 ( const char * str, int size = -1 )
//視str爲本地編碼,由操作系統默認編碼決定
QString QString::fromLocal8Bit ( const char * str, int size = -1 )