Qt5中读写配置文件

Qt中可以使用QSettings来进行简单的.ini配置文件的读写。

/* 初始化ini配置文件 */
QSettings configFile = new QSettings(QString("%1/app/app.ini").arg(QApplication::applicationDirPath()) ,QSettings::IniFormat);
configFile.setIniCodec(QTextCodec::codecForName("UTF-8"));

/* write */
configFile.beginGroup("PMC");

configFile.setValue("spindleKnifeNum", "BD0");
configFile.setValue("boxKnifeNum", "BR722");
configFile.endGroup();

/* read */
configFile.value("PMC/spindleKnifeNum",tr("")).toString();

要注意,以上代码,在第一阶段初始化配置文件过后,所有配置项已经在内存中了,下面的读取功能并不是实时计算的,实际上实时读取也是一件低效率的事情。

Qt5中使用JSON

Qt中将数据以JSON格式输出是非常愉快的:

QJsonObject obj;
obj.insert("numValue", 8);
obj.insert("strValue", "hello world");
qDebug() << obj;

QJsonDocument doc(obj);
qDebug(QString(doc.toJson(QJsonDocument::Compact)));

以及数组:

QJsonArray array;
for(int i = 0; i < no; i++){
    QJsonObject obj;
    obj.insert("id", alarms[i].alm_no);
    obj.insert("title", Utils::GBK2UTF(alarms[i].alm_msg));
    array.push_back(obj);
}
QJsonDocument doc(array);
return QString(doc.toJson(QJsonDocument::Compact));

虽说没有JAVA中的GSON框架之类的可以直接将Object转成JSON那么方便,但也简单实用,秉承Qt一贯的思维,突然想起上一篇利用回调函数实现Qt日志框架的文章,貌似这种思想在Qt里面是一脉相承的。

Qt5中使用日志系统

用惯了JAVA的log4j和log4j2,在Qt项目开发时也在试图寻找一种与之类似的全局的日志体系,将每个级别的日志分门别类、按照时间日期、按照日志文件大小统一规范起来。

经过各种尝试(期间还发现了log4qt),最后发现Qt5.4版本以后,自带了一个简单的日志回调函数,可以实现纯手工定制的日志框架,使用起来又简单又快捷,而且通过回调,可以自由定制业务逻辑。

1. 回调函数的设置

既然是回调函数,Qt肯定有一份默认的实现,这就是最简单的qDebug("xxx")所产生的效果,将调试信息通过标准输出流输出到终端上。但这显然不够用,我们需要自定义回调函数,方法如下:

函数声明
void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg);

上面代码不需要引入任何头文件,在Qt环境下直接可定义。

函数实现

上述函数声明后显然需要自己来实现,具体实现方式下面第2节再细说,这里先打好草稿。

void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg){
}
回调设置

以上,你只是定义了一个函数,并实现了它,整个Qt系统并不知道你需要用这个函数干什么,在哪里用。因此,要把这个函数在全局App启动时设置为日志系统的回调函数,设置方法如下:

qInstallMessageHandler(myMessageOutput);

2. 回调函数的实现

上面讲到实现那个回调函数,下面给出我的一份具体实现,代码很容易理解:

/**
 * 日志回调函数,按照日期进行日志归档
 * TODO: 以后可以完善将历史日志归档到文件夹的功能
 */
void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg){
    QString text;
    switch(type)
    {
    case QtDebugMsg:
        text = QString("DEBUG");
        break;

    case QtWarningMsg:
        text = QString("WARN");
        break;

    case QtCriticalMsg:
        text = QString("CRITICAL");
        break;

    case QtFatalMsg:
        text = QString("FATAL");
    }

    /* 截取源文件相对位置 */
    QString filepath = QString(context.file);
    int begin = filepath.indexOf('\\', 3);
    filepath = filepath.mid(begin + 1);

    QDateTime now = QDateTime::currentDateTime();
    QString context_info = QString("[%1:%2]").arg(filepath).arg(context.line);
    QString current_date_time = now.toString("hh:mm:ss");
    QString message = QString("%4 %1 %2:%3").arg(text).arg(context_info).arg(msg).arg(current_date_time);

    QString appPath = QApplication::applicationDirPath();
    QString logfile = QString("%1/app/logs/%2.log").arg(appPath).arg(now.toString("yyMMdd"));
    static QMutex mutex;
    mutex.lock();

    QFile file(logfile);
    file.open(QIODevice::WriteOnly | QIODevice::Append);
    QTextStream text_stream(&file);
    text_stream << message << "\r\n";
    file.flush();
    file.close();

    mutex.unlock();
}

上述代码,每次有调试指令时,就判断是什么级别的调试,然后在指定路径(./app/logs/)下向一个以「当前年月日.log」命名的日志文件中追加调试消息,如果该文件不存在则新建。

调试消息的格式我是参考log4j的,参见以下日志输出:

08:41:22 DEBUG [main.cpp:22]:Database Create Sucessfully!
08:41:27 DEBUG [main.cpp:51]:-16
08:41:27 DEBUG [main.cpp:52]:0
09:03:16 DEBUG [main.cpp:22]:Database Create Sucessfully!
09:03:16 WARN [main.cpp:31]:abc
09:03:21 DEBUG [main.cpp:52]:-16
09:03:21 DEBUG [main.cpp:53]:0
09:05:41 DEBUG [main.cpp:22]:Database Create Sucessfully!
09:05:41 DEBUG [main.cpp:31]:debg
09:05:41 WARN [main.cpp:32]:warn
09:05:41 CRITICAL [main.cpp:33]:critical
09:05:41 FATAL [main.cpp:34]:fatal
09:21:51 DEBUG [main.cpp:22]:Database Create Sucessfully!
09:21:51 DEBUG [main.cpp:31]:debg
09:21:51 WARN [main.cpp:32]:warn

Qt日志级别分为「Debug, Warnnig, Critical, Fatal」,其中Fatal不要轻易使用,因为不光会产生日志消息,还会自动结束整个进程。

程序代码任意位置,执行以下指令可进行日志输出:

qDebug("debg");
qWarning("中文");
qCritical("critical");
//qFatal("fatal");

以上代码需加入#include <QtDebug>头文件

至此,整个日志框架就这么简单地搭建了。我们可以继续完善这个回调函数,比如对各个级别的日志分别输出不同的文件;再比如,以上逻辑如果长期使用,./app/logs/路径下难免会产生大量以年月日.log命名的碎片文件,我们可以继续加入优化逻辑,比如执行时判断一下时间,并将本月以外的其他日志文件用zip格式压缩到以「年月.zip」命名的压缩文件中等等。

丁丁生于 1987.07.01 ,30岁,英文ID:newflydd

  • 现居住地 江苏 ● 泰州 ● 姜堰
  • 创建了 Jblog 开源博客系统
  • 坚持十余年的 独立博客 作者
  • 大学本科毕业后就职于 中国电信江苏泰州分公司,前两年从事Oracle数据库DBA工作,两年后公司精简技术人员,被安排到农村担任支局长(其本质是搞销售),于2016年因志向不合从国企辞职,在小城镇找了一份程序员的工作。
  • Git OSChina 上积极参与开源社区