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

相关推荐
明朝百晓生1 分钟前
Deep RL learning[2026/8]
开发语言·javascript·人工智能
weixin-a153003083161 小时前
python-装饰器
开发语言·python
我的xiaodoujiao1 小时前
快速学习Python基础知识详细图文教程17--类型注解和断点调试
开发语言·python·学习·测试工具
leoZ2313 小时前
AI 辅助开发的五道坎
开发语言·人工智能·视觉检测·bert·php·超分辨率重建·openvino
会周易的程序员3 小时前
aiDgePLC — IEC61131-3 ST PLC 虚拟机调试与运行环境
c++·物联网·虚拟机·st·工业协议·iec61131·梯形图
程序员老陆3 小时前
Qt的QThread::usleep和FFmpeg的libavutil模块的av_usleep哪个精度高一些?
开发语言·qt·ffmpeg·音视频
2601_963869954 小时前
【计算机毕业设计】基于Java的相框定制系统的设计与实现
java·开发语言·课程设计
名字还没想好☜4 小时前
Go 的 unsafe.Pointer 实战:零拷贝 []byte↔string 转换与三条铁律
开发语言·后端·golang·go·unsafe
Quz4 小时前
QML TextArea 入门(二):富文本与换行模式
qt
wuminyu5 小时前
JVM利用io_uring优化堆外内存性能原理剖析
java·linux·c语言·jvm·c++