这是我记录Qt学习过程心得文章的第一篇,也是前一段时间遇到的一个实实在在的问题,就是读取文本文件经常出现乱码,围绕读取文本文件时预先检测文本文件的编码格式,然后再在读取的时候自动设置对应的编码,我问遍度娘,遍寻CSDN,甚至请教了各路AI大神,终于解决了这个问题,可以通过检测文件头标志判断UTF-8、UTF-16LE/BE、GBK等格式,确保文本数据的使用QTextStream正确读取。
示例代码:
//获取文件编码格式函数
QTextCodec *Skysonya::getFileCharacterEncoding(const QString &fileName)
{//假定默认编码utf8EncodingFormat encoding = EncodingFormat::UTF8;QString codecName = "UTF-8"; //为了qDebug显示用QFile file(fileName);if (file.open(QIODevice::ReadOnly)){QByteArray firstBytes = file.read(3);qDebug() << "FirstBytes:" << firstBytes << Qt::endl;if (firstBytes.startsWith("\xEF\xBB\xBF")){// UTF-8 with BOMencoding = EncodingFormat::UTF8BOM;codecName = "UTF-8-BOM";}else if (firstBytes.startsWith("\xFF\xFE")){// UTF-16LEencoding = EncodingFormat::UTF16LE;codecName = "UTF-16LE";}else if (firstBytes.startsWith("\xFE\xFF")){// UTF-16BEencoding = EncodingFormat::UTF16BE;codecName = "UTF-16BE";}else{// ANSI or UTF-8QFile afile(fileName);afile.open(QIODevice::ReadOnly);QTextCodec::ConverterState converterState;QTextCodec *textcodec =QTextCodec::codecForName("utf-8"); //尝试用utf8转换,如果无效字符数大于0,则表示是ansi编码int num{};while (!afile.atEnd()){QByteArray line = afile.readLine(); //读取一行ASCII码qDebug() << "Line:" << line << Qt::endl;textcodec->toUnicode(line.constData(), line.size(), &converterState);num += converterState.invalidChars;if (num > 0) break;}encoding = (num > 0) ? EncodingFormat::ANSI : EncodingFormat::UTF8;codecName = (num > 0) ? "GB18030" : "UTF-8";}qDebug() << "FileEncoding:" << encoding << codecName << Qt::endl;file.close();}QTextCodec *textCodec;switch (encoding){case EncodingFormat::ANSI:textCodec = QTextCodec::codecForName("GB18030");codecName = "GB18030";break;case EncodingFormat::UTF16LE:textCodec = QTextCodec::codecForName("UTF-16LE");codecName = "UTF-16LE";break;case EncodingFormat::UTF16BE:textCodec = QTextCodec::codecForName("UTF-16BE");codecName = "UTF-16BE";break;case EncodingFormat::UTF8:textCodec = QTextCodec::codecForName("UTF-8");codecName = "UTF-8";break;case EncodingFormat::UTF8BOM:textCodec = QTextCodec::codecForName("UTF-8");//QTextCodec没有UTF-8-ROM这种编码格式codecName = "UTF-8-BOM";break;default:textCodec = QTextCodec::codecForName("UTF-8");break;}qDebug() << "TextCodec:" << textCodec << codecName << Qt::endl;return textCodec;
}
具体使用:
//用QTextStream读取文件,整体读取
QString Skysonya::openFileByStreamWhole(const QString &fileName)
{QFile file(fileName);if (!file.exists()){messageBox("Warning", tr("打开"), "文件不存在: " + file.errorString());return NULL;}if (!file.open(QIODevice::ReadOnly | QIODevice::Text)){messageBox("Warning", tr("打开"), "打开文件失败: " + file.errorString());return NULL;}QTextStream textStream(&file); //用文本流读取文件内容// textStream.setAutoDetectUnicode(true); //自动检测UnicodetextStream.setCodec(getFileCharacterEncoding(fileName));QString text = textStream.readAll(); //读取全部内容file.close();return text;
}
//打开
void MainWindow::slot_open_triggered()
{QAction *action = qobject_cast<QAction *>(sender());QString dlgTitle = "打开"; //对话框标题QString filter = "所有文件(*.txt)"; //文件过滤器QString currentFile = QFileDialog::getOpenFileName(this, dlgTitle, "", filter);QFileInfo fileinfo = QFileInfo(currentFile);setWindowTitle(wTitle + " - " + fileinfo.fileName());ui->plainMainEdit->setPlainText(skysonya.openFileByStreamWhole(currentFile));
}
我时写了一个类,类的头文件如下:
#ifndef SKYSONYA_H
#define SKYSONYA_H
#include <QDebug>
#include <QFile>
#include <QMessageBox>
#include <QObject>
#include <QPushButton>
#include <QString>
#include <QTextCodec>enum EncodingFormat
{ANSI,UTF16LE,UTF16BE,UTF8,UTF8BOM,
};class Skysonya : public QObject
{Q_OBJECTQ_ENUM(EncodingFormat)
public:explicit Skysonya(QObject *parent = nullptr);~Skysonya();QString doAppAbout(QString appName); //程序关于信息bool messageBox(QString msgType, QString dlgTitle, QString strInfo); //中文提示对话框QTextCodec *getFileCharacterEncoding(const QString &fileName); //获取文件编码格式函数QString openFileByIOWhole(const QString &fileName); //用QFile打开文件,整体读取QString openFileByIOLines(const QString &fileName); //用QFile打开文件,逐行读取QString openFileByStreamWhole(const QString &fileName); //用QTextStream读取文件,整体读取QString openFileByStreamLines(const QString &fileName); //用QTextStream读取文件,逐行读取bool saveFileByIOWhole(const QString &fileName, QString text); //用QFile保存文件,整体保存bool saveFileByStreamWhole(const QString &fileName, QString text); //用QTextStream保存文件,整体保存private:QString appVersion; //软件版本号QString buildTime; //程序构建时间QString qtVersion; // QT版本号QString fun_buildTime(); //获取程序构建时间
};#endif // SKYSONYA_H
完整的示例地址:https://download.csdn.net/download/skysonya_shisy/89861254