Название: Поиск слов в файле в Qt(Mutex)
Отправлено: stasJun от Октябрь 03, 2016, 12:11
Мне нужно написать консольную программу: Которая для заданного каталога файлов на диске находит файлы, содержащие заданное слово с использованием многопоточности. Программа должна вывести в столбик имена найденных файлов в алфавитном порядке. Я сделал програму но нужно ее было еще переделать и сделать с Mutexом, и я не знаю правильно ли я сделал с ним. Посмотрите и скажите верно ли все Хедер: #ifndef FIND_WORD_IN_FILE_THREAD_H #define FIND_WORD_IN_FILE_THREAD_H #include <QThread> #include <QString> #include <QtDebug> #include <QMutex> class FindWordInFileThread : public QThread { public: FindWordInFileThread(const std::vector<QString>& filePath, const QString& word, size_t startIndex, size_t numElements, std::vector<QString>& foundFiles, QMutex* mutex); virtual void run(); private: const std::vector<QString>& mFilePath; const QString mWord; size_t mStartIndex; size_t mNumElements; std::vector<QString>& mFoundFiles; QMutex* mMutex; }; #endif // FIND_WORD_IN_FILE_THREAD_H CPP: #include "FindWordInFileThread.h" #include <QFile> #include <QTextStream> #include <QFileInfo> #include <QMutexLocker> FindWordInFileThread::FindWordInFileThread(const std::vector<QString>& filePath, const QString& word, size_t startIndex, size_t numElements, std::vector<QString>& foundFiles, QMutex* mutex) : mFilePath(filePath) , mWord(word) , mStartIndex(startIndex) , mNumElements(numElements) , mFoundFiles(foundFiles) , mMutex(mutex) {} void FindWordInFileThread::run() { for (size_t index = mStartIndex; index < mStartIndex + mNumElements; ++index) { QFile file(mFilePath[index]); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return; QTextStream textStream(&file); while (!textStream.atEnd()) { QString line = textStream.readLine(); QMutexLocker locker(mMutex); if (line.contains(mWord, Qt::CaseInsensitive)) { mFoundFiles.push_back(QFileInfo(mFilePath[index]).fileName()); break; } } file.close(); } } Main: void FindWordInFiles(const QString& word, const size_t numThreads) { QMutex mutex; QTime time(QTime::currentTime()); std::srand(time.msecsSinceStartOfDay()); std::vector<QThread*> threads; threads.reserve(numThreads); QDirIterator dirIt("D:/11", QDirIterator::Subdirectories); std::vector<QString> paths; while (dirIt.hasNext()) { dirIt.next(); if (QFileInfo(dirIt.filePath()).isFile()) { if (QFileInfo(dirIt.filePath()).suffix() == "txt") paths.push_back(dirIt.filePath()); } } const std::vector<Range> ranges = GenerateRanges(numThreads, paths.size()); std::vector<QString> foundFiles; time.start(); for (size_t index = 0; index < numThreads; ++index) threads.push_back(new FindWordInFileThread(paths, word, ranges[index].mStart, ranges[index].mLength, foundFiles, &mutex)); for (size_t index = 0; index < numThreads; ++index) threads[index]->start(); for (size_t index = 0; index < numThreads; ++index) threads[index]->wait(); const int elapsedMs = time.elapsed(); std::sort(foundFiles.begin(), foundFiles.end()); qDebug() << "Elapsed time(ms): " << elapsedMs; for (size_t index = 0; index < foundFiles.size(); ++index) qDebug() << foundFiles[index]; for (size_t index = 0; index < numThreads; ++index) delete threads[index]; } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); const int idealThreadCount = QThread::idealThreadCount(); qDebug() << "One Thread:"; FindWordInFiles("pavlik", 1); qDebug() << ""; qDebug() << "Two Thread:"; FindWordInFiles("pavlik", 2); qDebug() << ""; qDebug() << "Optimal Thread: "; qDebug() <<"Ideal Thread Count:" << idealThreadCount; FindWordInFiles("pavlik", idealThreadCount); qDebug() << ""; qDebug() << "Twenty Thread: "; FindWordInFiles("pavlik", 20); return app.exec(); }
Название: Re: Поиск слов в файле в Qt(Mutex)
Отправлено: Igors от Октябрь 03, 2016, 12:40
QString line = textStream.readLine(); QMutexLocker locker(mMutex); if (line.contains(mWord, Qt::CaseInsensitive)) { mFoundFiles.push_back(QFileInfo(mFilePath[index]).fileName()); break; } } } Файлы у Вас не пересекаются, поэтому лучше захватывать мутекс если сработал if (перед mFoundFiles.push_back). Ну и многовато аргументов в конструкторе, напрашивается структура. А так вполне грамотно
Название: Re: Поиск слов в файле в Qt(Mutex)
Отправлено: stasJun от Октябрь 03, 2016, 13:40
QString line = textStream.readLine(); QMutexLocker locker(mMutex); if (line.contains(mWord, Qt::CaseInsensitive)) { mFoundFiles.push_back(QFileInfo(mFilePath[index]).fileName()); break; } } } Файлы у Вас не пересекаются, поэтому лучше захватывать мутекс если сработал if (перед mFoundFiles.push_back). Ну и многовато аргументов в конструкторе, напрашивается структура. А так вполне грамотно так вы имели введу? void FindWordInFileThread::run() { for (size_t index = mStartIndex; index < mStartIndex + mNumElements; ++index) { QFile file(mFilePath[index]); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return;
QTextStream textStream(&file); while (!textStream.atEnd()) { QString line = textStream.readLine(); if (line.contains(mWord, Qt::CaseInsensitive)) { QMutexLocker locker(mMutex); mFoundFiles.push_back(QFileInfo(mFilePath[index]).fileName()); break; } } file.close(); } }
Название: Re: Поиск слов в файле в Qt(Mutex)
Отправлено: qate от Октябрь 03, 2016, 16:48
не пойму зачем тут mutex есть список файлов - их можно отдать на поиск слова каждому потоку (что может быть не эффективно по чтению диска) или отдавать прочитанные данные каждому потоку через Qt Concurrent
Название: Re: Поиск слов в файле в Qt(Mutex)
Отправлено: Old от Октябрь 03, 2016, 16:57
не пойму зачем тут mutex
Этот мутекс защищает общий для всех потоков список имен файлов foundFiles, по сути результат работы всех потоков.
Название: Re: Поиск слов в файле в Qt(Mutex)
Отправлено: stasJun от Октябрь 03, 2016, 21:45
не пойму зачем тут mutex
Этот мутекс защищает общий для всех потоков список имен файлов foundFiles, по сути результат работы всех потоков. да вы правы, тут мы гарантируемо и контролиюем нормальную работу с файлом foundFiles. У меня норально и правильно работает код?
Название: Re: Поиск слов в файле в Qt(Mutex)
Отправлено: Kurles от Октябрь 03, 2016, 23:36
не пойму зачем тут mutex
Этот мутекс защищает общий для всех потоков список имен файлов foundFiles, по сути результат работы всех потоков. При использовании QtConcurrent не нужен же. Результат и так в основной поток попадет.
Название: Re: Поиск слов в файле в Qt(Mutex)
Отправлено: stasJun от Октябрь 03, 2016, 23:52
не пойму зачем тут mutex
Этот мутекс защищает общий для всех потоков список имен файлов foundFiles, по сути результат работы всех потоков. При использовании QtConcurrent не нужен же. Результат и так в основной поток попадет. не буду спорить. но! я не использую QtConcurrent. А использую Mutex. И попросил посмотреть правильно ли использую) А мне без обид только 1 пост по теме ответили, все остальное флуд, да полезный флуд, буду знать что есть QtConcurrent, но увы к моему вопросу не относиться.
Название: Re: Поиск слов в файле в Qt(Mutex)
Отправлено: stasJun от Октябрь 05, 2016, 20:37
Теперь мне нужно вместо консоли сделать в виде виджетта. 1)Подскажите как в виджетте директорию задавать? 2) Как сделать что бы в нижней результат выводить(туда вставлять результат поиска)? Спасибо Что я уже сделал: хедер: #ifndef FINDWORDINFILETHREAD_H #define FINDWORDINFILETHREAD_H
#include <QtWidgets>
class FindWordInFileThread : public QWidget { Q_OBJECT
public: FindWordInFileThread(QWidget *parent = 0); ~FindWordInFileThread(); public slots: void start();
private: int mStart; };
#endif // FINDWORDINFILETHREAD_H СПП: #include "FindWordInFileThread.h"
FindWordInFileThread::FindWordInFileThread(QWidget *parent) : QWidget(parent) { setWindowTitle("Find word in file thread"); QLabel* selectDirectory = new QLabel("Select directory:"); QPushButton* start = new QPushButton("&Start"); connect(start, SIGNAL(clicked()), SLOT(start()));
QLineEdit* text = new QLineEdit;
QVBoxLayout* layout = new QVBoxLayout; layout->addWidget(selectDirectory); layout->addWidget(start); layout->addWidget(text); setLayout(layout); resize(500, 300); } void FindWordInFileThread::start() {
}
FindWordInFileThread::~FindWordInFileThread() {
} меин: #include "FindWordInFileThread.h" #include <QApplication>
int main(int argc, char *argv[]) { QApplication app(argc, argv); FindWordInFileThread findWordInFileThread; findWordInFileThread.show();
return app.exec(); }
Название: Re: Поиск слов в файле в Qt(Mutex)
Отправлено: Kurles от Октябрь 05, 2016, 21:29
Теперь мне нужно вместо консоли сделать в виде виджетта. 1)Подскажите как в виджетте директорию задавать? 2) Как сделать что бы в верхней части о задавать директорию а в нижней результат выводить?
Если с точки зрения "дизайна", то я бы сделал примерно так: (http://image.prntscr.com/image/3b143fb98bcc4141b67aa1d6d510de06.png) В нижнем QGroupBox находиться QListWidet. Можно заменить на QTextEdit. Ну и вместо ручного кодирования использовал бы дизайнер. Или по условию задачи нужно ручками виджеты на форме выставлять? Если да, то использовал бы сгенереный дизайнером код с небольшими правками =)
Название: Re: Поиск слов в файле в Qt(Mutex)
Отправлено: Old от Октябрь 05, 2016, 21:48
Я бы еще lineedit добавил для ввода искомого слова. Может оказаться полезным. :)
Название: Re: Поиск слов в файле в Qt(Mutex)
Отправлено: stasJun от Октябрь 05, 2016, 22:43
Теперь мне нужно вместо консоли сделать в виде виджетта. 1)Подскажите как в виджетте директорию задавать? 2) Как сделать что бы в верхней части о задавать директорию а в нижней результат выводить?
Если с точки зрения "дизайна", то я бы сделал примерно так: (http://image.prntscr.com/image/3b143fb98bcc4141b67aa1d6d510de06.png) В нижнем QGroupBox находиться QListWidet. Можно заменить на QTextEdit. Ну и вместо ручного кодирования использовал бы дизайнер. Или по условию задачи нужно ручками виджеты на форме выставлять? Если да, то использовал бы сгенереный дизайнером код с небольшими правками =) а скиньте код как вы сделали виджет, да нужно ручками самому делать
Название: Re: Поиск слов в файле в Qt(Mutex)
Отправлено: stasJun от Октябрь 06, 2016, 10:34
Я бы еще lineedit добавил для ввода искомого слова. Может оказаться полезным. :)
я сделал так открытие директории: QString str = QFileDialog::getExistingDirectory(0, "Directory Dialog", ""); но как мне сделать так как на картинке в Kurles ? я про это говорю(как на фото)
Название: Re: Поиск слов в файле в Qt(Mutex)
Отправлено: Kurles от Октябрь 06, 2016, 14:59
а скиньте код как вы сделали виджет, да нужно ручками самому делать
C++ (Qt) CustomWidget::CustomWidget(QWidget *parent) : QWidget(parent) { /* нужные указатели, такие как toolButtonSelectDir, * pushButtonStart, lineEditDirName и listWidgetResult * можно (нужно) сдеалать переменными класса */ QVBoxLayout *verticalLayout2; QHBoxLayout *horizontalLayout2; QGroupBox *groupBox; QHBoxLayout *horizontalLayout; QLineEdit *lineEditDirName; QToolButton *toolButtonSelectDir; QPushButton *pushButtonStart; QGroupBox *groupBox2; QVBoxLayout *verticalLayout; QListWidget *listWidgetResult; verticalLayout2 = new QVBoxLayout(this); verticalLayout2->setSpacing(6); verticalLayout2->setContentsMargins(11, 11, 11, 11); horizontalLayout2 = new QHBoxLayout(); horizontalLayout2->setSpacing(6); groupBox = new QGroupBox(this); horizontalLayout = new QHBoxLayout(groupBox); horizontalLayout->setSpacing(6); horizontalLayout->setContentsMargins(11, 11, 11, 11); lineEditDirName = new QLineEdit(groupBox); horizontalLayout->addWidget(lineEditDirName); toolButtonSelectDir = new QToolButton(groupBox); horizontalLayout->addWidget(toolButtonSelectDir); horizontalLayout2->addWidget(groupBox); pushButtonStart = new QPushButton(this); horizontalLayout2->addWidget(pushButtonStart); verticalLayout2->addLayout(horizontalLayout2); groupBox2 = new QGroupBox(this); verticalLayout = new QVBoxLayout(groupBox2); verticalLayout->setSpacing(6); verticalLayout->setContentsMargins(11, 11, 11, 11); listWidgetResult = new QListWidget(groupBox2); verticalLayout->addWidget(listWidgetResult); verticalLayout2->addWidget(groupBox2); setWindowTitle(tr("Поиск файла")); toolButtonSelectDir->setText("..."); pushButtonStart->setText(tr("Начать")); lineEditDirName->setText(tr("d:/some_dir")); resize(600, 600); }
Код, сгенеренный uic'ом, и немного подправленный.
Название: Re: Поиск слов в файле в Qt(Mutex)
Отправлено: stasJun от Октябрь 06, 2016, 15:57
у вас в коде нигде не пишеться: Выбор директории и результат поиска я сделал)) QGroupBox* groupBoxFirst = new QGroupBox("&Select directory:"); QGroupBox* groupBoxSecond = new QGroupBox("&Result found:");
Название: Re: Поиск слов в файле в Qt(Mutex)
Отправлено: stasJun от Октябрь 06, 2016, 16:20
часть кода(что переделал) и фото програмы: FindWordInFileThread::FindWordInFileThread(QWidget *parent) : QWidget(parent) { setWindowTitle("Find word in file thread"); QGroupBox* groupBoxFirst = new QGroupBox("&Select directory:");
QPushButton* pushButtonStart = new QPushButton("&Start"); QVBoxLayout* vLayoutFirst = new QVBoxLayout(this); vLayoutFirst->setSpacing(6); vLayoutFirst->setContentsMargins(11, 11, 11, 11);
QHBoxLayout* hLayoutFirst = new QHBoxLayout(this); hLayoutFirst->setSpacing(6); hLayoutFirst->addWidget(groupBoxFirst); hLayoutFirst->addWidget(pushButtonStart); vLayoutFirst->addLayout(hLayoutFirst);
QLineEdit* lineEditDirName = new QLineEdit(groupBoxFirst); lineEditDirName->setText(tr("D://")); QToolButton* toolButtonSelectDir = new QToolButton(groupBoxFirst); toolButtonSelectDir->setText("Open");
QHBoxLayout* hLayoutSecond = new QHBoxLayout(groupBoxFirst); hLayoutSecond->setSpacing(6); hLayoutSecond->setContentsMargins(11, 11, 11, 11); hLayoutSecond->addWidget(lineEditDirName); hLayoutSecond->addWidget(toolButtonSelectDir);
QGroupBox* groupBoxSecond = new QGroupBox("&Found files:"); QVBoxLayout* vLayoutSecond = new QVBoxLayout(groupBoxSecond); vLayoutSecond->setSpacing(6); vLayoutSecond->setContentsMargins(11, 11, 11, 11);
QListWidget* listWidgetResult = new QListWidget(groupBoxSecond); vLayoutSecond->addWidget(listWidgetResult); vLayoutFirst->addWidget(groupBoxSecond); resize(600, 600);
}
Название: Re: Поиск слов в файле в Qt(Mutex)
Отправлено: stasJun от Октябрь 06, 2016, 17:14
А есть в QT функция которая открывает после нажати директории где можна задать папку где искать файлы? qfiledialog я думал использовать, но я не вижу там такой функции. и еще такое Kurles у Вас в окне директории и у меня можна вручну задавать путь? там что хочешь можна зараз писать. Реализацию книпки Open я так сделал: void FindWordInFileThread::open() { QString fileName = QFileDialog::getOpenFileName(this, tr(""), "",tr("Text Files (*.txt)"));
if (fileName != "") { QFile file(fileName); if (!file.open(QIODevice::ReadOnly)) { QMessageBox::critical(this, tr("Error"), tr("Could not open file")); return; } QTextStream in(&file); QTextEdit* textEdit; textEdit->setText(in.readAll()); file.close(); } } но оно крешится. И хз по чему
Название: Re: Поиск слов в файле в Qt(Mutex)
Отправлено: Bepec от Октябрь 06, 2016, 18:28
третий параметр вроде в getOpenFileName задаёт директорию, которая откроется для выбора файла. Вам нужно её лишь запоминать.
Название: Re: Поиск слов в файле в Qt(Mutex)
Отправлено: stasJun от Октябрь 13, 2016, 15:10
Я немного доделал прогу( додал прогрес бар) но он работать не хочет нормально. Может вы увидите почему он не хочет работать. 1)Мне нужно знать размер всех файлов в которых я ищу чтобы прогрес бар норм работал, зараз он ни как не реагирует. Есть функция которая узнает какой размер файла? 2) При нажатии старт кнопка должна поменятся на стоп(работает), но когда жму на стоп не останавливается ((( Код: #include "FindFilesWidget.h" #include "FindWordInFileThread.h"
struct Range { Range(size_t start, size_t length);
size_t mStart; size_t mLength; };
Range::Range(size_t start, size_t length) : mStart(start) , mLength(length) {}
std::vector<Range> GenerateRanges(size_t numRanges, size_t numFiles) { std::vector<Range> ranges; ranges.reserve(numRanges);
const size_t minLength = numFiles / numRanges; const size_t modulo = numFiles % numRanges;
for (size_t index = 0; index < modulo; ++index) ranges.push_back(Range(0, minLength + 1));
for (size_t index = modulo; index < numRanges; ++index) ranges.push_back(Range(0, minLength));
for (size_t index = 1; index < numRanges; ++index) ranges[index].mStart = ranges[index - 1].mStart + ranges[index - 1].mLength;
return ranges; }
FindFilesWidget::FindFilesWidget(QWidget *parent) : QWidget(parent) , mActionState(ActionState::WAITING) { setWindowTitle("Search Files");
QVBoxLayout* vLayout = new QVBoxLayout(this); vLayout->setSpacing(6); vLayout->setContentsMargins(11, 11, 11, 11); vLayout->addWidget(createSelectDirectoryGroup()); vLayout->addWidget(createSearchWordGroup()); vLayout->addWidget(createProgressBarGroup()); vLayout->addWidget(createFoundFilesGroup()); setLayout(vLayout);
resize(600, 600); }
void FindFilesWidget::startClicked() { mActionState = ActionState::RUNNING; mStartButton->setText("&Cancel"); const int idealThreadCount = QThread::idealThreadCount(); std::vector<QThread*> threads; threads.reserve(idealThreadCount);
QDirIterator dirIt(mSearchDirectoryLine->text(), QDirIterator::Subdirectories); std::vector<QString> paths; while (dirIt.hasNext()) { dirIt.next(); if (QFileInfo(dirIt.filePath()).isFile()) { if (QFileInfo(dirIt.filePath()).suffix() == "txt") paths.push_back(dirIt.filePath()); } } const std::vector<Range> ranges = GenerateRanges(idealThreadCount, paths.size()); std::vector<QString> foundFiles;
for (size_t index = 0; index < idealThreadCount; ++index) threads.push_back(new FindWordInFileThread(paths, mSearchWordLine->text(), ranges[index].mStart, ranges[index].mLength, foundFiles)); for (size_t index = 0; index < idealThreadCount; ++index) threads[index]->start(); for (size_t index = 0; index < idealThreadCount; ++index) threads[index]->wait();
std::sort(foundFiles.begin(), foundFiles.end());
for (size_t index = 0; index < idealThreadCount; ++index) delete threads[index];
mFoundFilesList->clear(); for (size_t index = 0; index < foundFiles.size(); ++index) mFoundFilesList->addItem(foundFiles[index]); } void FindFilesWidget::cancelClicked() { close(); } void FindFilesWidget::progressClicked() { const int number = 10; mProgressBar->setRange(0, 5); mProgressBar->setMinimumWidth(200); mProgressBar->setAlignment(Qt::AlignCenter); mProgressBar->setValue(number); }
void FindFilesWidget::selectDirectoryClicked() { QString selectedDirectory = QFileDialog::getExistingDirectory(this, tr("Open Directory"), mSearchDirectoryLine->text(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); mSearchDirectoryLine->setText(selectedDirectory); }
QGroupBox* FindFilesWidget::createSelectDirectoryGroup() { QGroupBox* selectDirectoryGroup = new QGroupBox("&Select directory:"); QPushButton* selectDirectoryButton = new QPushButton("Select", selectDirectoryGroup); mSearchDirectoryLine = new QLineEdit(tr("D:/"), selectDirectoryGroup);
QHBoxLayout* hLayout = new QHBoxLayout(); hLayout->setSpacing(6); hLayout->addWidget(mSearchDirectoryLine); hLayout->addWidget(selectDirectoryButton);
connect(selectDirectoryButton, SIGNAL(clicked()), SLOT(selectDirectoryClicked()));
selectDirectoryGroup->setLayout(hLayout); return selectDirectoryGroup; }
QGroupBox* FindFilesWidget::createSearchWordGroup() { QGroupBox* searchWordGroup = new QGroupBox("&Search word:"); mSearchWordLine = new QLineEdit(searchWordGroup); mStartButton = new QPushButton("&Start");
QHBoxLayout* hLayout = new QHBoxLayout(); hLayout->setSpacing(6); hLayout->setContentsMargins(11, 11, 11, 11); hLayout->addWidget(mSearchWordLine); hLayout->addWidget(mStartButton);
connect(mStartButton, SIGNAL(clicked()), SLOT(startClicked()));
searchWordGroup->setLayout(hLayout); return searchWordGroup; }
QGroupBox* FindFilesWidget::createProgressBarGroup() { QGroupBox* progressBarGroup = new QGroupBox("&Progress Bar:"); mProgressBar = new QProgressBar(progressBarGroup);
QHBoxLayout* hLayout = new QHBoxLayout(); hLayout->setSpacing(6); hLayout->setContentsMargins(11, 11, 11, 11); hLayout->addWidget(mProgressBar);
connect(mStartButton, SIGNAL(clicked()), SLOT(progressClicked()));
progressBarGroup->setLayout(hLayout); return progressBarGroup; }
QGroupBox* FindFilesWidget::createFoundFilesGroup() { QGroupBox* foundFilesGroup = new QGroupBox("&Found files:"); mFoundFilesList = new QListWidget(foundFilesGroup);
QHBoxLayout* hLayout = new QHBoxLayout(); hLayout->setSpacing(6); hLayout->setContentsMargins(11, 11, 11, 11); hLayout->addWidget(mFoundFilesList);
foundFilesGroup->setLayout(hLayout); return foundFilesGroup; }
Хедер: #ifndef FINDFILESWIDGET_H #define FINDFILESWIDGET_H
#include <QtWidgets>
class FindFilesWidget : public QWidget { Q_OBJECT
public: enum ActionState { WAITING, RUNNING, STOPED, }; FindFilesWidget(QWidget* parent = 0);
public slots: void startClicked(); void cancelClicked(); void selectDirectoryClicked(); void progressClicked();
private: QGroupBox* createSelectDirectoryGroup(); QGroupBox* createSearchWordGroup(); QGroupBox* createProgressBarGroup(); QGroupBox* createFoundFilesGroup();
QLineEdit* mSearchDirectoryLine; QListWidget* mFoundFilesList; QLineEdit* mSearchWordLine; QPushButton* mStartButton; QProgressBar* mProgressBar; ActionState mActionState; };
#endif // FINDFILESWIDGET_H
Название: Re: Поиск слов в файле в Qt(Mutex)
Отправлено: stasJun от Октябрь 15, 2016, 12:19
Old, Kurles, Igors вы не знаете ответы на мои вопросы? я уже по другому пробывал делать и резальтат тотже не работает прогрес бар
|