中天建设集团门户网站,网站建设上机考试题目,wordpress商城制作教程,企业建设网站需要注意什么手续由于实际生产需要#xff0c;软件系统的运行#xff0c;会产生大量的日志文件#xff0c;有时候一天就能产生超过百万条log记录#xff0c;那么为了能够处理日志文件#xff0c;查询并且找到我们想要的报错信息#xff0c;因此不得不考虑怎么实现#xff0c;打开大日志文…由于实际生产需要软件系统的运行会产生大量的日志文件有时候一天就能产生超过百万条log记录那么为了能够处理日志文件查询并且找到我们想要的报错信息因此不得不考虑怎么实现打开大日志文件的可行方法。 在这里我采用的是内存映射的方式去读取文件的日志信息。代码部分如下所示
QFile file(big_path);
qint64 fileSize file.size(); // 获取文件的大小
uchar *data file.map(0, fileSize); // 将文件的全部内容映射到内存中返回一个指向该内容的指针
file.close();//文件的关闭不会影响到我们后续的内存映射部分。if (data) { // 如果映射成功QElapsedTimer timer;timer.start();message.clear();QString text QString::fromUtf8((char *)data, fileSize);file.unmap(data); // 取消映射ui-plainTextEdit-appendPlainText(text);messagetext.split(\n);ui-label-setText(识别完成,时间为QString::number(timer.elapsed()/1000)s);QTextCursor cursor ui-plainTextEdit-textCursor();cursor.movePosition(QTextCursor::Start);ui-plainTextEdit-setTextCursor(cursor);//是为了实现将鼠标对应的光标移动到第一行也就是日志的最上面。}else { // 如果映射失败qDebug() 映射失败错误信息 file.errorString(); // 打印错误信息QMessageBox::information(this,提示,映射失败错误信息:file.errorString());}
QT里面的内存映射的机制如下
内存映射Memory Mapping是一种将文件或者设备的一部分映射到进程的虚拟地址空间的技术这样可以方便地对文件或者设备进行读写操作而不需要使用系统调用或者缓冲区。QT提供了QFileDevice类和QFile类来支持内存映射的功能相关的方法有
map(qint64 offset, qint64 size, QFileDevice::MemoryMapFlags flags NoOptions)这个方法可以将文件或者设备的一部分映射到内存中并返回一个指向该内存区域的指针。参数offset表示映射的起始位置size表示映射的大小flags表示映射的选项比如是否保护、是否共享等。unmap(uchar *address)这个方法可以取消内存映射并释放相关的资源。参数address表示要取消映射的内存区域的指针。isMapped(uchar *address)这个方法可以检查一个内存区域是否是由map()方法映射的。参数address表示要检查的内存区域的指针。
除此之外还有如何搜寻自己想要的信息方式有以下几种
首先第一种是遍历循环每一条log信息并在其中进行搜索但是这样的搜索方式只能用于小日志文件当文件内容过多的时候这种搜索方式的时间度是很大的。
利用for或者while等循环来遍历每一条的log信息。但是这个遍历出来的速度和效率是十分慢的。
代码实现如下所示 qDebug()pp;path_textpp;message.clear();// 创建一个QFile对象关联用户选择的文件QFile file(path_text);// 以只读模式打开文件if (file.open(QIODevice::ReadOnly)) {// 循环读取每一行// 创建一个QTextStream对象关联文件QTextStream in(file);// 设置流对象的编码为UTF-8in.setCodec(UTF-8);while (!file.atEnd()) {// 读取一行内容转换为QString类型QString line QString::fromUtf8(file.readAll());// 处理或显示每一行内容message.append(line);qDebug()line;ui-plainTextEdit-appendPlainText(line);//appendPlainText}// 关闭文件file.close();}else{qDebug() error;}
这里为了加快读取的速度还专门设置了文件的编码形式为UTF-8来减少QT的自动识别编码的时间而且这个读取文件的方式是用的Qtextstream的方式来的。
第二种就是由于笔记本上面自带的软件记事本而想到的一种方式就是记事本的查询功能的实现因此考虑到将同样的功能实现在QT里面。
另外上面也说过了需要实现log文件的显示在这里我采用的是Qplaintext控件来显示大量的文本信息。注意在这里不能采用textedit编辑器来显示大容量的文本它会出现错误。
我的界面设计如下所示 因为我需要查找信息因此要将用户的输入的信息进行筛选所以我还用了一个linedit的控件来获取输入内容。
实现查找信息的功能的代码部分如下图所示
QString goalui-lineEdit-text();bool resultui-plainTextEdit-find(goal);//向下寻找
// bool result2ui-plainTextEdit-find(goal,QTextDocument::FindBackward);//向回找if(result){QTextCursor cursor ui-plainTextEdit-textCursor();qDebug()cursor.blockNumber();shunxu.push_back(cursor.blockNumber());return true;}return false;
我通过QT给的封装函数find函数它会帮助我找到符合我需要的内容的所在下一行并且将光标移动到这一行然后我再利用QTextCursor来获取当前光标所在行数的位置并且打印保存下来。
因为我在前面的ui-plaintext里面将获取得到的log内容通过QString里面的split(“\n”)函数的方式将原来的QString的内容按行分割成QStringList的形式保存下来。然后我通过前面获得的行号将对应的Qtring的行的内容取出来并且显示ui-plaintext上面即可。
这种遍历方式也最多只能达到同时遍历几百行的样子。
第二种方式也可以优化比如可以分成两部分多开一个线程让其中一个从最后开始寻找主线程从第一行开始寻找最后将找到的日志行数汇总到一起。相当于是一个简单的二分法寻找。
最后第三种方式同时遍历很多行数
这个方法的时间复杂度是O(n)也就是随着元素的数量增加所需的时间也会线性增加。如果您想要一次遍历很多行也就是提高查找的效率您可以使用以下的方法
使用QHash或者QMap类来存储每个元素和它们的索引或者计数这样可以实现O(1)或者O(log n)的查找时间但是需要额外的空间来存储哈希表或者映射表。使用QStringList类的filter()方法来过滤出包含指定内容的元素然后使用indexOf()方法或者contains()方法来获取它们的索引或者计数这样可以减少遍历的次数但是需要创建一个新的QStringList对象。使用QRegularExpression类来创建一个正则表达式对象表示您想要查找的内容然后使用QStringList类的indexOf()方法或者contains()方法来查找匹配该正则表达式的元素并获取它们的索引或者计数这样可以更灵活地定义查找的条件但是需要注意正则表达式的语法和效率。
代码部分如下所示
#include QApplication
#include QPlainTextEdit
#include QDebug
#include QRegularExpressionint main(int argc, char *argv[]) {QApplication app(argc, argv);QPlainTextEdit *edit new QPlainTextEdit(); // create a QPlainTextEdit objectedit-setPlainText(This is a test text for QPlainTextEdit.\nIt may have multiple lines.\nSome lines may contain the word function.); // set some plain textQString text edit-toPlainText(); // get the plain text contentQStringList lines text.split(\n); // split the text by newlineQRegularExpression re(\\bfunction\\b); // create a regular expression object, using \b to match word boundariesint count 0; // the number of lines that match the regular expressionint index -1; // the index of the first matching linewhile ((index lines.indexOf(re, index 1)) ! -1) { // loop through the lines, using indexOf() method to find the matching linecount; // increase the countqDebug() Found re.pattern() at line index 1; // print the line number, add 1 because the index is zero-based}qDebug() Total count lines match re.pattern(); // print the total countreturn app.exec();
}QHash和QMap都是Qt提供的关联容器类它们可以用来存储键值对的数据结构。它们的主要区别是
QHash是基于哈希表实现的它的查找速度通常比QMap更快但是它的键是以任意顺序存储的而且它对键的类型有更多的要求需要提供operator()和qHash()函数。QMap是基于跳表实现的它的查找速度通常比QHash慢一些但是它的键是以升序顺序存储的而且它对键的类型只需要提供operator()函数。
如果您需要时间度最小的一种遍历方法我建议您使用QHash并且使用STL风格的迭代器来遍历。这样可以避免创建额外的对象并且可以直接访问键和值。例如
QHashQString, QStringList hash;
// insert some data into hash
QHashQString, QStringList::const_iterator i hash.constBegin();
while (i ! hash.constEnd()) {QString key i.key();QStringList value i.value();// do something with key and valuei;
}