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

相关推荐
北极象2 分钟前
Go语言处理HTTP下载中EOFFailed
开发语言·http·golang
superior tigre5 分钟前
C++学习:六个月从基础到就业——C++11/14:decltype关键字
c++·学习
技术流浪者8 分钟前
C/C++实践(十)C语言冒泡排序深度解析:发展历史、技术方法与应用场景
c语言·数据结构·c++·算法·排序算法
tyatyatya18 分钟前
MATLAB 自然语言处理入门教程
开发语言·matlab·自然语言处理
Funny-Boy29 分钟前
Reactor (epoll实现基础)
服务器·网络·c++
20242817李臻38 分钟前
20242817-李臻-课下作业:Qt和Sqlite
jvm·qt·sqlite
I AM_SUN43 分钟前
98. 验证二叉搜索树
数据结构·c++·算法·leetcode
tmacfrank1 小时前
Java 原生网络编程(BIO | NIO | Reactor 模式)
java·开发语言·网络
沐土Arvin1 小时前
深入理解 requestIdleCallback:浏览器空闲时段的性能优化利器
开发语言·前端·javascript·设计模式·html
tyatyatya1 小时前
MATLAB的神经网络工具箱
开发语言·神经网络·matlab