実際の運用ニーズにより、ソフトウェア システムの操作により大量のログ ファイルが生成され、場合によっては 1 日に 100 万を超えるログ レコードが生成されることがあります。そのため、ログ ファイルを処理できるようにするには、クエリを実行して、エラー情報が必要な場合は、それを実装する方法、大きなログ ファイルを開くための実行可能な方法を検討する必要があります。
ここでは、メモリ マッピングを使用してファイルのログ情報を読み取ります。コード部分は次のようになります。
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);
message=text.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): このメソッドはメモリ マッピングをキャンセルし、関連リソースを解放します。パラメータアドレスは、アンマップされるメモリ領域のポインタを示します。
- isMapped(uchar *address): このメソッドは、メモリ領域がmap()メソッドによってマップされているかどうかを確認できます。パラメータアドレスは、チェック対象のメモリ領域のポインタを示します。
さらに、必要な情報を検索する方法がいくつかあります。
まず、1つ目はログ情報をたどって検索する方法ですが、この検索方法はログファイルが小さい場合にのみ使用でき、ファイル数が多すぎると検索に時間がかかります。
for や while などのループを使用して、各ログ情報を調べます。しかし、この横断の速度と効率は非常に遅いです。
コードの実装は次のとおりです。
qDebug()<<pp;
path_text=pp;
message.clear();
// 创建一个QFile对象,关联用户选择的文件
QFile file(path_text);
// 以只读模式打开文件
if (file.open(QIODevice::ReadOnly)) {
// 循环读取每一行
// 创建一个QTextStream对象,关联文件
QTextStream in(&file);
// 设置流对象的编码为UTF-8
in.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 メソッドを使用します。
2つ目は、ノートブックに付属するソフトウェアのメモ帳があるため、メモ帳のクエリ機能を実現する方法が思いつきますので、QTでも同様の機能を実現することが考えられます。
また、前述の通りログファイルの表示を実現する必要があるので、ここではQplaintextコントロールを使用して大量のテキスト情報を表示します。ここで大容量のテキストを表示するには textedit エディタを使用できず、エラーが発生することに注意してください。
私のインターフェースのデザインは次のようになります。
情報を検索する必要があるため、ユーザーの入力情報をフィルターする必要があるため、入力コンテンツを取得するために lineedit コントロールも使用します。
情報を検索する機能を実装するコード部分を次の図に示します。
QString goal=ui->lineEdit->text();
bool result=ui->plainTextEdit->find(goal);//向下寻找
// bool result2=ui->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では取得したログの内容を取得し、QStringのsplit("\n")関数を使って元のQStringの内容をQStringListに行ごとに分割して保存するためです。次に、先ほど取得した行番号から該当するQtring行の内容を取り出し、ui->plaintext上に表示します。
この走査方法では、同時に最大数百行までしか到達できません。
2番目の方法も最適化できます。たとえば、2つの部分に分割し、もう1つのスレッドを開いて、一方のスレッドは最後から検索を開始し、メインスレッドは最初の行から検索を開始します。最後に、見つかったログ行の数を合計します。これは単純な二分探索と同等です。
最後に 3 番目の方法: 同時に多くの行を走査する
この方法の時間計算量は O(n) です。つまり、要素の数が増加するにつれて、必要な時間は直線的に増加します。一度に多くの行をスキャンする場合、つまり検索の効率を向上させる場合は、次の方法を使用できます。
- QHash または QMap クラスを使用して、各要素とそのインデックスまたはカウントを格納します。これにより、検索時間は O(1) または O(log n) になりますが、ハッシュ テーブルまたはマッピング テーブルを格納するために追加のスペースが必要になります。
- QStringList クラスの filter() メソッドを使用して、指定されたコンテンツを含む要素をフィルターで除外し、次に、indexOf() メソッドまたは contains() メソッドを使用してインデックスまたはカウントを取得します。これにより、トラバーサルの数を減らすことができますが、新しい QStringList オブジェクト。
- Q RegularExpression クラスを使用して、検索対象を表す正規表現オブジェクトを作成し、QStringList クラスの IndexOf() メソッドまたは contains() メソッドを使用して、正規表現に一致する要素を検索し、そのインデックスまたはカウントを取得します。これにより、検索条件をより柔軟に定義できますが、正規表現の構文と効率に注意する必要があります。
コード部分は次のようになります。
#include <QApplication>
#include <QPlainTextEdit>
#include <QDebug>
#include <QRegularExpression>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QPlainTextEdit *edit = new QPlainTextEdit(); // create a QPlainTextEdit object
edit->setPlainText("This is a test text for QPlainTextEdit.\nIt may have multiple lines.\nSome lines may contain the word function."); // set some plain text
QString text = edit->toPlainText(); // get the plain text content
QStringList lines = text.split("\n"); // split the text by newline
QRegularExpression re("\\bfunction\\b"); // create a regular expression object, using \b to match word boundaries
int count = 0; // the number of lines that match the regular expression
int index = -1; // the index of the first matching line
while ((index = lines.indexOf(re, index + 1)) != -1) { // loop through the lines, using indexOf() method to find the matching line
count++; // increase the count
qDebug() << "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 count
return app.exec();
}
QHash と QMap はどちらも Qt によって提供される関連コンテナ クラスであり、キーと値のペアのデータ構造を格納するために使用できます。それらの主な違いは次のとおりです。
- QHash はハッシュ テーブルに基づいて実装されます。その検索速度は通常 QMap よりも高速ですが、キーは任意の順序で保存され、キーのタイプについてより多くの要件があります。operator==() と qHash() を提供する必要があります。 ) 関数。
- QMap はジャンプ テーブルに基づいて実装されており、検索速度は通常 QHash よりも遅いですが、キーは昇順で格納され、キー タイプに対応する演算子<() 関数を提供するだけで済みます。
最小限の時間で走査する方法が必要な場合は、QHash を使用し、STL スタイルのイテレータを使用して走査することをお勧めします。これにより、余分なオブジェクトの作成が回避され、キーと値に直接アクセスできるようになります。例えば:
QHash<QString, QStringList> hash;
// insert some data into hash
QHash<QString, QStringList>::const_iterator i = hash.constBegin();
while (i != hash.constEnd()) {
QString key = i.key();
QStringList value = i.value();
// do something with key and value
++i;
}