QT 自动识别文本文件的编码格式

这是我记录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

相关推荐
aq55356007 分钟前
PHP vs Python:30秒看懂核心区别
开发语言·python·php
我是无敌小恐龙9 分钟前
Java SE 零基础入门Day01 超详细笔记(开发前言+环境搭建+基础语法)
java·开发语言·人工智能·opencv·spring·机器学习
小灰灰搞电子21 分钟前
Qt 中的队列解析
qt
香蕉鼠片31 分钟前
MFC是什么
c++·mfc
码云数智-大飞1 小时前
零基础微信小程序制作平台哪个好
开发语言
心态与习惯1 小时前
Julia 初探,及与 C++,Java,Python 的比较
java·c++·python·julia·比较
神仙别闹1 小时前
基于 MATLAB 实现的 DCT 域的信息隐藏
开发语言·matlab
techdashen1 小时前
Go 标准库 JSON 包迎来重大升级:encoding/json/v2 实验版来了
开发语言·golang·json
小欣加油1 小时前
leetcode2078 两栋颜色不同且距离最远的房子
数据结构·c++·算法·leetcode·职场和发展
我真不是小鱼2 小时前
cpp刷题打卡记录30——轮转数组 & 螺旋矩阵 & 搜索二维矩阵II
数据结构·c++·算法·leetcode