这是我记录Qt学习过程心得文章的第一篇,也是前一段时间遇到的一个实实在在的问题,就是读取文本文件经常出现乱码,围绕读取文本文件时预先检测文本文件的编码格式,然后再在读取的时候自动设置对应的编码,我问遍度娘,遍寻CSDN,甚至请教了各路AI大神,终于解决了这个问题,可以通过检测文件头标志判断UTF-8、UTF-16LE/BE、GBK等格式,确保文本数据的使用QTextStream正确读取。

示例代码:

//获取文件编码格式函数
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;
}

具体使用

//用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;
}
//打开
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_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

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部