这是我记录Qt学习过程心得文章的第一篇,也是前一段时间遇到的一个实实在在的问题,就是读取文本文件经常出现乱码,围绕读取文本文件时预先检测文本文件的编码格式,然后再在读取的时候自动设置对应的编码,我问遍度娘,遍寻CSDN,甚至请教了各路AI大神,终于解决了这个问题,可以通过检测文件头标志判断UTF-8、UTF-16LE/BE、GBK等格式,确保文本数据的使用QTextStream正确读取。
示例代码:
cpp
//获取文件编码格式函数
QTextCodec *Skysonya::getFileCharacterEncoding(const QString &fileName)
{
//假定默认编码utf8
EncodingFormat 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 BOM
encoding = EncodingFormat::UTF8BOM;
codecName = "UTF-8-BOM";
}
else if (firstBytes.startsWith("\xFF\xFE"))
{
// UTF-16LE
encoding = EncodingFormat::UTF16LE;
codecName = "UTF-16LE";
}
else if (firstBytes.startsWith("\xFE\xFF"))
{
// UTF-16BE
encoding = EncodingFormat::UTF16BE;
codecName = "UTF-16BE";
}
else
{
// ANSI or UTF-8
QFile 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;
}
具体使用**:**
cpp
//用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); //自动检测Unicode
textStream.setCodec(getFileCharacterEncoding(fileName));
QString text = textStream.readAll(); //读取全部内容
file.close();
return text;
}
cpp
//打开
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));
}
我时写了一个类,类的头文件如下:
cpp
#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_OBJECT
Q_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