Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: daimon от Март 13, 2012, 03:42



Название: Остановка рекурсии поиска файлов [РЕШЕНО]
Отправлено: daimon от Март 13, 2012, 03:42
есть рекурсивная функция поиска файлов, как остановить поиск?

(задача - мягко остановить поток, без terminate)

Код
C++ (Qt)
QStringList CFileFindThread::getListFilesFind( const QString &pathr, QStringList filters )
{
QString path;
if(pathr.isEmpty()) path = QDir::currentPath();
     else path = pathr;
QDir dir(path);
if(!dir.exists())
{
return QStringList();
}
 
QStringList listFiles = QStringList();
 
 
foreach (QString file, dir.entryList(filters))
{
listFiles << QFileInfo(dir, file).absoluteFilePath();
 
}
 
m_countFiles+= dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot).count();
 
foreach (QString subDir, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot))
{
listFiles << getListFilesFind(path + QDir::separator() + subDir, filters);
m_currentNumberFile ++;
emit progress(m_currentNumberFile *100 / m_countFiles);
}
 
 
return listFiles;
}
 
void CFileFindThread::run()
{
 
m_FilesList = getListFilesFind(m_Path,m_FilterNames);
 
 
}


Название: Re: Остановка рекурсии поиска файлов
Отправлено: Bepec от Март 13, 2012, 06:59
Внутрь каждого foreach втулить условие на флаг и прерывание цикла.

Написать слот, который меняет значение флага.

Вызвать в нужный момент слот, который поменяет значение флага, который прервёт циклы, которые завершившись пройдут дальше по run и далее поток выполнив run завершится 200% мягко и корректно.


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 13, 2012, 13:37
Внутрь каждого foreach втулить условие на флаг и прерывание цикла.

Написать слот, который меняет значение флага.

Вызвать в нужный момент слот, который поменяет значение флага, который прервёт циклы, которые завершившись пройдут дальше по run и далее поток выполнив run завершится 200% мягко и корректно.

оно то так, но тут может быть маленькая задержка в выходе из рекурсии - пока рекурсия заново свернётся, пройдёт время, например, если папок больше 100000 будет просматривать


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 13, 2012, 13:40
Цитировать
Внутрь каждого foreach втулить условие на флаг и прерывание цикла.

думаю лучше прерывать работу функции по return QStringList(), но так потеряю список уже найденных файлов


Название: Re: Остановка рекурсии поиска файлов
Отправлено: Bepec от Март 13, 2012, 13:43
Цитировать
Внутрь каждого foreach втулить условие на флаг и прерывание цикла.
[/color]

Непонятно?

В любом случае будет задержка, заключающаяся в том, чтобы поток успел дойти до мест остановок (условий). Задержка будет незначительной, если правильно расставить условия.

Мгновенно можно завершить поток - terminate/exit.


update:
прерывай цикл, потом хоть на голове плясать можно ;) включая и ретурн QStringList.


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 13, 2012, 13:44
Внутрь каждого foreach втулить условие на флаг и прерывание цикла.

Написать слот, который меняет значение флага.

Вызвать в нужный момент слот, который поменяет значение флага, который прервёт циклы, которые завершившись пройдут дальше по run и далее поток выполнив run завершится 200% мягко и корректно.
Интересно а если вместо прерывания циклов кинуть эксепшн и вверху его ловить это будет быстрее? Просто интересно какие будут плюсы и минусы =).


Название: Re: Остановка рекурсии поиска файлов
Отправлено: mutineer от Март 13, 2012, 13:45
Мгновенно можно завершить поток - terminate/exit.

exit() мгновенно не завершит - управление должно дойти до ивент-лупа


Название: Re: Остановка рекурсии поиска файлов
Отправлено: mutineer от Март 13, 2012, 13:46
Интересно а если вместо прерывания циклов кинуть эксепшн и вверху его ловить это будет быстрее? Просто интересно какие будут плюсы и минусы =).

terminate будет быстрее - эксепш не особо быстрая штука


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 13, 2012, 13:50
Внутрь каждого foreach втулить условие на флаг и прерывание цикла.

Написать слот, который меняет значение флага.

Вызвать в нужный момент слот, который поменяет значение флага, который прервёт циклы, которые завершившись пройдут дальше по run и далее поток выполнив run завершится 200% мягко и корректно.
Интересно а если вместо прерывания циклов кинуть эксепшн и вверху его ловить это будет быстрее? Просто интересно какие будут плюсы и минусы =).
выглядело красиво бы, но всё равно задержка при свёртывании рекурсии


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 13, 2012, 13:55
выглядело красиво бы, но всё равно задержка при свёртывании рекурсии
А может еще проще вообще избавиться от рекурсии? Взять список в котором будут параметры и в цикле выполнять эти параметры пока не закончатся. И в итоге вместо рекурсии просто будешь в список добавлять параметры.


Название: Re: Остановка рекурсии поиска файлов
Отправлено: Bepec от Март 13, 2012, 14:07
Ещё красивее было бы привести архитектуру в порядок :)

Или как вариант - дать пользователю возможность дальше работать, не выключая поток :D


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 13, 2012, 14:09
выглядело красиво бы, но всё равно задержка при свёртывании рекурсии
А может еще проще вообще избавиться от рекурсии? Взять список в котором будут параметры и в цикле выполнять эти параметры пока не закончатся. И в итоге вместо рекурсии просто будешь в список добавлять параметры.

подробнее пожалуйста..


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 13, 2012, 14:17
Ещё красивее было бы привести архитектуру в порядок :)

Или как вариант - дать пользователю возможность дальше работать, не выключая поток :D

подробнее пожалуйста...


Название: Re: Остановка рекурсии поиска файлов
Отправлено: Igors от Март 13, 2012, 14:25
Не вижу откуда возьмется "задержка свертывания рекурсии" если в каждый цикл просто вставить
Код
C++ (Qt)
if (m_StopFlag) return listFiles;
 
Скорее всего пауза вызвана чем-то другим (напр очередь забита сигналами прогресса).  

И еще не понял
Код
C++ (Qt)
QStringList listFiles = QStringList();   // какой в этом скрытый смысл ?
QStringList listFiles;   // почему не так?
 


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 13, 2012, 14:27
вопрос по архитектуре использования потока такого.

что лучше:

1. создать поток один раз и просто чередовать функции start, terminate (своя функция, меняет флаг для останова рекурсии)
     плюс - один раз выделил память и работать с одним потоком,
     минус - если поток не используется, висит в памяти, только одна ветка поиска файлов
2. создавать каждый раз извне (где он используется) и после отработки рекурсии делать deleteLater() и также в terminate (моя функция)  вызывать удаление потока deleteLater(),
    плюс - в памяти не висит просто так, можно запустить независимые ветки поиска файлов,
    минус - время на выделение памяти при создании ветки


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 13, 2012, 14:30
Цитировать
QStringList listFiles = QStringList();   // какой в этом скрытый смысл ?

все переменные нужно иниционализировать)), хотя можно и убрать


Название: Re: Остановка рекурсии поиска файлов
Отправлено: mutineer от Март 13, 2012, 14:31
Цитировать
QStringList listFiles = QStringList();   // какой в этом скрытый смысл ?

все переменные нужно иниционализировать)), хотя можно и убрать

Лист сам инициализируется в своем конструкторе. А так у тебя создается и удаляется лишний объект


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 13, 2012, 14:37
Цитировать
QStringList listFiles = QStringList();   // какой в этом скрытый смысл ?

все переменные нужно иниционализировать)), хотя можно и убрать

Лист сам инициализируется в своем конструкторе. А так у тебя создается и удаляется лишний объект

согласен


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 13, 2012, 14:40
вопрос по архитектуре использования потока такого.

что лучше:

1. создать поток один раз и просто чередовать функции start, terminate (своя функция, меняет флаг для останова рекурсии)
     плюс - один раз выделил память и работать с одним потоком,
     минус - если поток не используется, висит в памяти, только одна ветка поиска файлов
2. создавать каждый раз извне (где он используется) и после отработки рекурсии делать deleteLater() и также в terminate (моя функция)  вызывать удаление потока deleteLater(),
    плюс - в памяти не висит просто так, можно запустить независимые ветки поиска файлов,
    минус - время на выделение памяти при создании ветки



Название: Re: Остановка рекурсии поиска файлов
Отправлено: Igors от Март 13, 2012, 14:50
вопрос по архитектуре использования потока такого.

что лучше:
В таких случаях лучше спросить (самого себя) "а их может быть 2 или больше?". Напр где-то началось (одно) сканирование, а в др месте потребовалось еще одно (напр с др фолдером). Если такая ситуевина планируется, то второй вариант 


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 13, 2012, 15:05
подробнее пожалуйста..
Да чего подробнее то, вот на скорую руку переписал, но не проверял правильность.
Код:
QStringList getListFilesFind(const QString &pathr, QStringList filters)
{
    QStack<QString> dirs;
    QString path;
    QStringList listFiles;
    if(pathr.isEmpty())
        path = QDir::currentPath();
    else
        path = pathr;
    dirs.push(path);
    while (!dirs.isEmpty()) {
        path = dirs.pop();
        QDir dir(path);
        if(!dir.exists())
            continue;

        foreach (QString file, dir.entryList(filters))
            listFiles << QFileInfo(dir, file).absoluteFilePath();

        foreach (QString subDir, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)){
            dirs.push(path + QDir::separator() + subDir);
        }
    }
    return listFiles;
}


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 13, 2012, 15:47
подробнее пожалуйста..
Да чего подробнее то, вот на скорую руку переписал, но не проверял правильность.
Код:
QStringList getListFilesFind(const QString &pathr, QStringList filters)
{
    QStack<QString> dirs;
    QString path;
    QStringList listFiles;
    if(pathr.isEmpty())
        path = QDir::currentPath();
    else
        path = pathr;
    dirs.push(path);
    while (!dirs.isEmpty()) {
        path = dirs.pop();
        QDir dir(path);
        if(!dir.exists())
            continue;

        foreach (QString file, dir.entryList(filters))
            listFiles << QFileInfo(dir, file).absoluteFilePath();

        foreach (QString subDir, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)){
            dirs.push(path + QDir::separator() + subDir);
        }
    }
    return listFiles;
}

работать работает, но вот непонятно чего так

Код
C++ (Qt)
m_countFiles+= dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot).count();
 
foreach (QString file, dir.entryList(filters))
{
m_currentNumberFile ++;
emit progress(m_currentNumberFile *100 / m_countFiles);
listFiles << QFileInfo(dir, file).absoluteFilePath();
}

доходит до 100% за 10 сек, хотя поиску ещё идёт как минимум 3 минуты, при моём рекурсивном варианте поиска прогресс менялся и бывало 96 97 98 и аж в конце 100
что не так?


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 13, 2012, 15:59
подробнее пожалуйста..
Да чего подробнее то, вот на скорую руку переписал, но не проверял правильность.
Код:
QStringList getListFilesFind(const QString &pathr, QStringList filters)
{
    QStack<QString> dirs;
    QString path;
    QStringList listFiles;
    if(pathr.isEmpty())
        path = QDir::currentPath();
    else
        path = pathr;
    dirs.push(path);
    while (!dirs.isEmpty()) {
        path = dirs.pop();
        QDir dir(path);
        if(!dir.exists())
            continue;

        foreach (QString file, dir.entryList(filters))
            listFiles << QFileInfo(dir, file).absoluteFilePath();

        foreach (QString subDir, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)){
            dirs.push(path + QDir::separator() + subDir);
        }
    }
    return listFiles;
}

работать работает, но вот непонятно чего так

Код
C++ (Qt)
m_countFiles+= dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot).count();
 
foreach (QString file, dir.entryList(filters))
{
m_currentNumberFile ++;
emit progress(m_currentNumberFile *100 / m_countFiles);
listFiles << QFileInfo(dir, file).absoluteFilePath();
}

доходит до 100% за 10 сек, хотя поиску ещё идёт как минимум 3 минуты, при моём рекурсивном варианте поиска прогресс менялся и бывало 96 97 98 и аж в конце 100
что не так?
Ну дык ты же подсчитываешь количество директорий. В твоем рекурсивном после нахождения каждой директории в ней происходил поиск и поэтому время между нахождением следующей директории был долгий. В моем же варианте сразу все директории верхнего уровня находятся и если вложенных директорий нет то и будет 100%. Щас набросаю как я это вижу...


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 13, 2012, 16:02
я поправил

Код
C++ (Qt)
m_countFiles += dir.entryList(filters).count();

чтобы плюсовать количество файлов по фильтру именно текущей директории

но всё равно 99-100 100-99


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 13, 2012, 16:09
я поправил

Код
C++ (Qt)
m_countFiles += dir.entryList(filters).count();

чтобы плюсовать количество файлов по фильтру именно текущей директории

но всё равно 99-100 100-99
Вот это попробуй, вроде должно работать, но прогресс будет иногда уменьшатся когда будет происходить нахождение новых файлов:
Код:
QStringList getListFilesFind(const QString &pathr, QStringList filters)
{
    QStack<QString> dirs;
    QString path;
    QStringList listFiles;
    qint32 countFiles = 1;
    qint32 currentNumberFile = 0;
    qint32 progress = 0;
    qint32 progressOld = 0;
    if(pathr.isEmpty())
        path = QDir::currentPath();
    else
        path = pathr;
    dirs.push(path);
    while (!dirs.isEmpty()) {
        path = dirs.pop();
        QDir dir(path);
        countFiles += dir.entryList(QDir::NoDotAndDotDot).count();
        ++currentNumberFile;
        if(!dir.exists())
            continue;

        foreach (QString file, dir.entryList(filters)) {
            ++currentNumberFile;
            listFiles << QFileInfo(dir, file).absoluteFilePath();
            progress = currentNumberFile * 100 / countFiles;
            if (progressOld != progress) {
                progressOld = progress;
                emit progress(progress);
            }
        }

        foreach (QString subDir, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)){
            dirs.push(path + QDir::separator() + subDir);
        }
    }
    return listFiles;
}


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 13, 2012, 16:21
по нулям всё, emit не идёт


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 13, 2012, 16:24
по нулям всё, emit не идёт
Да ступил, вместо
Код:
countFiles += dir.entryList(QDir::NoDotAndDotDot).count();
надо было
Код:
countFiles += dir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot).count();


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 13, 2012, 16:30
по нулям всё, emit не идёт
Да ступил, вместо
Код:
countFiles += dir.entryList(QDir::NoDotAndDotDot).count();
надо было
Код:
countFiles += dir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot).count();

всё равно не так, попытаюсь объяснить, так мы считаем количество всех файлов в папке, а текущий номер файла идёт по списку количества файлов в директории по фильтру, итог один - прогресс всегда показывает 30-40%

думаю нужно написать countFiles += dir.entryList(filters).count();

и всё равно всегда 100%
мда сурово

видимо прийдёться поставить прогресбар на анимацию))))


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 13, 2012, 16:33
по нулям всё, emit не идёт
Да ступил, вместо
Код:
countFiles += dir.entryList(QDir::NoDotAndDotDot).count();
надо было
Код:
countFiles += dir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot).count();

всё равно не так, попытаюсь объяснить, так мы считаем количество всех файлов в папке, а текущий номер файла идёт по списку количества файлов в директории по фильтру, итог один - прогресс всегда показывает 30-40%

думаю нужно написать countFiles += dir.entryList(filters).count();

и всё равно всегда 100%
мда сурово
Дело в том что по мере поиска количество файлов увеличивается и изначально мы не знаем сколько их. Вот последний вариант, больше я не хочу пробовать:
Код:
QStringList getListFilesFind(const QString &pathr, QStringList filters)
{
    QStack<QString> dirs;
    QString path;
    QStringList listFiles;
    qint32 countFiles = 1;
    qint32 currentNumberFile = 0;
    qint32 progress = 0;
    qint32 progressOld = 0;
    if(pathr.isEmpty())
        path = QDir::currentPath();
    else
        path = pathr;
    dirs.push(path);
    while (!dirs.isEmpty()) {
        path = dirs.pop();
        QDir dir(path);
        countFiles += dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot).count();
        ++currentNumberFile;

        progress = currentNumberFile * 100 / countFiles;
        if (progressOld != progress) {
            progressOld = progress;
            emit progress(progress);
        }

        if(!dir.exists())
            continue;

        foreach (QString file, dir.entryList(filters)) {
            listFiles << QFileInfo(dir, file).absoluteFilePath();
        }

        foreach (QString subDir, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)){
            dirs.push(path + QDir::separator() + subDir);
        }
    }
    return listFiles;
}


Название: Re: Остановка рекурсии поиска файлов
Отправлено: Igors от Март 13, 2012, 16:37
entryList явно не дешевый вызов и делать его дважды-трижды не следует


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 13, 2012, 16:41
логику понял - смотрим не по файлам, а директориям и выставляем процент исходя из пройденной директории


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 13, 2012, 16:41
entryList явно не дешевый вызов и делать его дважды-трижды не следует
Да, эту строку удалить:
Код:
countFiles += dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot).count();
А вот тут изменить:
Код:
foreach (QString subDir, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)){
    ++countFiles;
    dirs.push(path + QDir::separator() + subDir);
}
Но все равно прогресс будет плохим если будет большая вложенность директорий. Тогда прогресс быстро достигнет 90% и потом медленно будет двигаться к 100% и если попадется директория с большим количеством чем было найдено то прогресс уменьшится до половины.


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 13, 2012, 16:51
да теперь вроде прогрессбар пришёл в порядок, показывает хоть 99 и уже на финише только 100

да но всё равно пока есть  dir.entryList вызов 2 раза

может в циклах просто проверять есть ли это файл (по фильтру) или директория
и вообще всё в один цикл закинуть: заталкивание файлов в список и забивание стека новыми директориями


Название: Re: Остановка рекурсии поиска файлов
Отправлено: Igors от Март 13, 2012, 16:53
Борьба с прогрессом непонятна. В любом случае сколько осталось - неизвестно, так зачем показывать пользователю заведомо неправдивые проценты? Лучше давать 0 (индикатор бегает туда-сюда) + где-то в уголке малевать сколько файлов поймано


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 13, 2012, 16:54
Борьба с прогрессом непонятна. В любом случае сколько осталось - неизвестно, так зачем показывать пользователю заведомо неправдивые проценты? Лучше давать 0 (индикатор бегает туда-сюда) + где-то в уголке малевать сколько файлов поймано
вариант))


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 13, 2012, 16:55
да теперь вроде прогрессбар пришёл в порядок, показывает хоть 99 и уже на финише только 100

да но всё равно пока есть  dir.entryList вызов 2 раза

может в циклах просто проверять есть ли это файл (по фильтру) или директория
и вообще всё в один цикл закинуть: заталкивание файлов в список и забивание стека новыми директориями
Ну дык вот так вроде с одним вызовом должно работать:
Код:
        foreach (QString file, dir.entryList(filters)) {
            if (QFileInfo(dir, file).isDir()){
                ++countFiles;
                dirs.push(path + QDir::separator() + dir);    
            } else {
                listFiles << QFileInfo(dir, file).absoluteFilePath();
            }
        }
Борьба с прогрессом непонятна. В любом случае сколько осталось - неизвестно, так зачем показывать пользователю заведомо неправдивые проценты? Лучше давать 0 (индикатор бегает туда-сюда) + где-то в уголке малевать сколько файлов поймано
Да я того же мнения.

изменения: поправил опечатку.


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 13, 2012, 17:07
не работает по 2 причинам:

1. нет оператора + для QDir (думаю нужно возвращать путь директории)
2. при таком условии форича мы не видим папок вроде (всё на фильтре держится)


думаю форич поставить на весь список директории кроме "." и ".."

но тут делема, что прийдёться всегда проверять принадлежит ли разрешение файла списку фильтров


Название: Re: Остановка рекурсии поиска файлов
Отправлено: Странник от Март 13, 2012, 20:23
почему не использовать QDirIterator?


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 14, 2012, 13:22
этот код при большом поиске не находит около 100 файлов
Код
C++ (Qt)
foreach (QString file, dir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot))
{
QFileInfo temp(dir,file);
 
if(temp.isDir())
dirs.push(path + QDir::separator() + file);
else if(m_FilterNames.contains("*." + temp.completeSuffix()))
listFiles << QFileInfo(dir, file).absoluteFilePath();
}
 

а так на 1 файл больше
Код
C++ (Qt)
foreach (QString file, dir.entryList(filters)) {
           listFiles << QFileInfo(dir, file).absoluteFilePath();
       }
 
       foreach (QString subDir, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)){
           dirs.push(path + QDir::separator() + subDir);
       }

остальная часть кода ниже

« Ответ #28 : Март 13, 2012, 15:33 »

что не так подскажите?


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 14, 2012, 13:28
что не так подскажите?
А чем отличаются не найденные файлы с найденными? И чем отличается лишний найденный от остальных нелишних?


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 14, 2012, 13:31
что не так подскажите?
А чем отличаются не найденные файлы с найденными? И чем отличается лишний найденный от остальных нелишних?

значит total commander нашел, а я нет и с ним сравниваю

как-бы точно 50000 сравнить не могу, смотрю по количеству найденных))


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 14, 2012, 13:33
что не так подскажите?
А чем отличаются не найденные файлы с найденными? И чем отличается лишний найденный от остальных нелишних?

значит total commander нашел, а я нет и с ним сравниваю
Может там скрытые файлы есть, системные, ссылки и т.д. А ты их естественно пропускаешь.


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 14, 2012, 13:35
что не так подскажите?
А чем отличаются не найденные файлы с найденными? И чем отличается лишний найденный от остальных нелишних?

значит total commander нашел, а я нет и с ним сравниваю
Может там скрытые файлы есть, системные, ссылки и т.д. А ты их естественно пропускаешь.

исключено (проверяю по фильтру *.h *.cpp), на данный момент не могу понять разницу двух алгоритмов - один из них верно почти ищет (лишний файл находит), другой - ошибается очень сильно (всё в одном цикле)


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 14, 2012, 14:08
что не так подскажите?
А чем отличаются не найденные файлы с найденными? И чем отличается лишний найденный от остальных нелишних?

значит total commander нашел, а я нет и с ним сравниваю
Может там скрытые файлы есть, системные, ссылки и т.д. А ты их естественно пропускаешь.

исключено (проверяю по фильтру *.h *.cpp), на данный момент не могу понять разницу двух алгоритмов - один из них верно почти ищет (лишний файл находит), другой - ошибается очень сильно (всё в одном цикле)
Дык выложи название лишнего файла и пропущенных файлов.


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 14, 2012, 14:11
самое смешное на маленьком количестве файлов - работают оба нормально, но свыше 50000 файлов - ошибаются, отследить потерю нереально))), вот почему и прошу посмотреть разницу в коде

можно попробовать писать найденные файлы в текстовый файл а потом какой-то софтиной сравнивать текст....


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 14, 2012, 14:16
самое смешное на маленьком количестве файлов - работают оба нормально, но свыше 50000 файлов - ошибаются, отследить потерю нереально))), вот почему и прошу посмотреть разницу в коде

можно попробовать писать найденные файлы в текстовый файл а потом какой-то софтиной сравнивать текст....
Да все очень просто, сделай две функции и запускай их по очереди. У тебя получится два списка файлов. И дальше из второго удаляешь все файлы что есть в первом ну и наоборот тоже и если все получится прозреваешь.


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 14, 2012, 14:18
самое смешное на маленьком количестве файлов - работают оба нормально, но свыше 50000 файлов - ошибаются, отследить потерю нереально))), вот почему и прошу посмотреть разницу в коде

можно попробовать писать найденные файлы в текстовый файл а потом какой-то софтиной сравнивать текст....
Да все очень просто, сделай две функции и запускай их по очереди. У тебя получится два списка файлов. И дальше из второго удаляешь все файлы что есть в первом ну и наоборот тоже и если все получится прозреваешь.

хитро пробую))

первое, что увидел - методу с одним циклом не нравятся конструкции файлов с несколькими точками и большими буквами под разрешения

попробовал сделать замер по времени: один цикл иногда выигрывает на 1 секунду, а иногда и на 2 минуты на 50000 файлов ничего не пойму почему

думаю просто другой алгоритм срабатывает сразу после первого и может происходит кеширование как-то


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 14, 2012, 15:54
первое, что увидел - методу с одним циклом не нравятся конструкции файлов с несколькими точками и большими буквами под разрешения
Там где лишний файл находит разобрался? Если скопировал то что я выкладывал то я там первоначальную директорию тоже считал. Щас сам попробую проверить =).


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 14, 2012, 16:12
первое, что увидел - методу с одним циклом не нравятся конструкции файлов с несколькими точками и большими буквами под разрешения
Там где лишний файл находит разобрался? Если скопировал то что я выкладывал то я там первоначальную директорию тоже считал. Щас сам попробую проверить =).
нет не разобрался пока ещё)

сейчас максимально подгоню алгоритмы к идентичности, чтобы эмит шел только при проходе всей директории (может из-за этого пока алгоритм с одни циклом проигрывает)

на данный момент алгоритм с одним циклом ищет правильно количество файлов, но медленнее работает, ищу почему с 2 циклами находит лишний файл

Код
C++ (Qt)
QStringList CFileFindThread::getListFilesFind( const QString &pathr, QStringList filters )
{
QStack<QString> dirs;
QString path;
QStringList listFiles;
 
m_countFiles = 0;
 
if(pathr.isEmpty())
path = QDir::currentPath();
else
path = pathr;
dirs.push(path);
 
 
while (!dirs.isEmpty()) {
path = dirs.pop();
QDir dir(path);
 
if(!dir.exists())
continue;
 
foreach (QString file, dir.entryList(filters)) ///////////видит папку как файл!!!!!!!!!!!!!!!!!!!!! если имя microsoft.cpp
              {
listFiles << QFileInfo(dir, file).absoluteFilePath();
m_countFiles++;
}
 
emit currentCountFiles(m_countFiles);
 
foreach (QString subDir, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)){
dirs.push(path + QDir::separator() + subDir);
}
}
 
return listFiles;
}

Код
C++ (Qt)
QStringList CFileFindThread::getListFilesFindOld( const QString &pathr, QStringList filters )
{
 
QStack<QString> dirs;
QString path;
QStringList listFiles;
 
m_countFiles = 0;
 
if(pathr.isEmpty())
path = QDir::currentPath();
else
path = pathr;
dirs.push(path);
 
 
while (!dirs.isEmpty()) {
path = dirs.pop();
QDir dir(path);
 
if(!dir.exists())
continue;
 
foreach (QString file, dir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot))// медленней работает алгоритма с двумя циклами
{
QFileInfo temp(dir,file);
 
if(temp.isDir())
dirs.push(path + QDir::separator() + file);
 
else if(m_FilterNames.contains("*." + temp.suffix(), Qt::CaseInsensitive))
{
listFiles << QFileInfo(dir, file).absoluteFilePath();
m_countFiles++;
emit currentCountFiles(m_countFiles);
}
}
 
}
return listFiles;
}

нашел ошибку алгоритма с двумя циклами, лишний файл - папка


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 14, 2012, 16:51
нет не разобрался пока ещё)
Вот собрал красивенький тестовый проект, ищет одинаковое количество что с одни что с двумя циклами. И с одним циклом у меня быстрее:
http://rghost.ru/37019164 (http://rghost.ru/37019164).


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 14, 2012, 17:03
всё поправил - ищет правильные файлы, сделал замер по работе, дебаг версия, релиз версия ищет в 2 раза дольше, думаю из-за очень частого эмита!!!!!!
Код
C++ (Qt)
QStringList CFileFindThread::getListFilesFind( const QString &pathr, QStringList filters )
{
QStack<QString> dirs;
QString path;
QStringList listFiles;
 
m_countFiles = 0;
 
if(pathr.isEmpty())
path = QDir::currentPath();
else
path = pathr;
dirs.push(path);
 
 
while (!dirs.isEmpty()) {
path = dirs.pop();
QDir dir(path);
 
if(!dir.exists())
continue;
 
foreach (QString file, dir.entryList(filters, QDir::Files))
              {
listFiles << QFileInfo(dir, file).absoluteFilePath();
m_countFiles++;
}
 
emit currentCountFiles(m_countFiles);
 
foreach (QString subDir, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)){
dirs.push(path + QDir::separator() + subDir);
}
}
 
return listFiles;
}

Код
C++ (Qt)
QStringList CFileFindThread::getListFilesFindOld( const QString &pathr, QStringList filters )
{
 
QStack<QString> dirs;
QString path;
QStringList listFiles;
 
m_countFiles = 0;
 
if(pathr.isEmpty())
path = QDir::currentPath();
else
path = pathr;
dirs.push(path);
 
 
while (!dirs.isEmpty()) {
path = dirs.pop();
QDir dir(path);
 
if(!dir.exists())
continue;
 
foreach (QString file, dir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot))// медленней работает алгоритма с двумя циклами
{
QFileInfo temp(dir,file);
 
if(temp.isDir())
dirs.push(path + QDir::separator() + file);
 
else if(m_FilterNames.contains("*." + temp.suffix(), Qt::CaseInsensitive))
{
listFiles << QFileInfo(dir, file).absoluteFilePath();
m_countFiles++;
emit currentCountFiles(m_countFiles);
}
}
 
}
return listFiles;
}




Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 14, 2012, 17:08
всё поправил - ищет правильные файлы, сделал замер по работе, дебаг версия
Release верси. Слева один цикл, справа два цикла. Время в миллисекундах.


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 14, 2012, 17:44
поправил вроде везде - скрыл ключи для скрытых файлов и системных, поставил фильтр на h, cpp


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 14, 2012, 18:08
поправил вроде везде - скрыл ключи для скрытых файлов и системных, поставил фильтр на h, cpp
Блин я попутал, там слева это два цикла, а справа один. Вроде все правильно, с одним циклом быстрее.
Только вот почему у меня с одним циклом медленнее получается?

добавлено:
Хотя нет, на очень большом количестве файлов одиночный цикл быстрее.


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 14, 2012, 18:47
поправил вроде везде - скрыл ключи для скрытых файлов и системных, поставил фильтр на h, cpp
Блин я попутал, там слева это два цикла, а справа один. Вроде все правильно, с одним циклом быстрее.
Только вот почему у меня с одним циклом медленнее получается?

добавлено:
Хотя нет, на очень большом количестве файлов одиночный цикл быстрее.

Код
C++ (Qt)
QStringList CFileFindThread::getListFilesFindOld( const QString &pathr, QStringList filters )
{
 
QStack<QString> dirs;
QString path;
QStringList listFiles;
 
m_countFiles = 0;
 
if(pathr.isEmpty())
path = QDir::currentPath();
else
path = pathr;
dirs.push(path);
 
 
while (!dirs.isEmpty()) {
path = dirs.pop();
QDir dir(path);
 
if(!dir.exists())
continue;
 
foreach (QString file, dir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot))
{
QFileInfo temp(dir,file);
 
if(temp.isDir())
dirs.push(path + QDir::separator() + file);
 
else if(m_FilterNames.contains("*." + temp.suffix(), Qt::CaseInsensitive))
{
listFiles << QFileInfo(dir, file).absoluteFilePath();
m_countFiles++;
emit currentCountFiles(m_countFiles);
}
}
 
}
return listFiles;
}

при 51768 файлов на 3 секунды медленней от 2 циклов, не пойму чего?


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 14, 2012, 19:16
при 51768 файлов на 3 секунды медленней от 2 циклов, не пойму чего?
Ты на холостом ходе проверь. Может тормозит проверка подходящего имени?


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 14, 2012, 19:34
при 51768 файлов на 3 секунды медленней от 2 циклов, не пойму чего?
Ты на холостом ходе проверь. Может тормозит проверка подходящего имени?
отправляю С:/ и фильтр *.cpp *.h

как тестировать?


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 14, 2012, 19:36
при 51768 файлов на 3 секунды медленней от 2 циклов, не пойму чего?
Ты на холостом ходе проверь. Может тормозит проверка подходящего имени?
отправляю С:/ и фильтр *.cpp *.h

как тестировать?
без фильтра.

добавлено:
Блин во я туплю. Одиночный цикл тупит из-за того что в нем каждый цикл создается объект QFileInfo и проиходит проверка на директорию. Это походу очень много времени занимает. Так что с двумя циклами наверно будет все-же быстрее.


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 14, 2012, 19:48
Вот правильный одиночный цикл, сразу уделывает двойной =):
Код
C++ (Qt)
foreach (QFileInfo file, dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) {
   if(file.isDir()) {
       ++currentNumberFile;
       dirs.push(file.absoluteFilePath());
   } else {
       *listFiles << file.absoluteFilePath();
   }
}


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 14, 2012, 20:28
Вот правильный одиночный цикл, сразу уделывает двойной =):
Код
C++ (Qt)
foreach (QFileInfo file, dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) {
   if(file.isDir()) {
       ++currentNumberFile;
       dirs.push(file.absoluteFilePath());
   } else {
       *listFiles << file.absoluteFilePath();
   }
}
тут есть одна маленькая вещь, которая важна - фильтр


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 14, 2012, 20:46
тут есть одна маленькая вещь, которая важна - фильтр
Так реализуй такой фильтр как тебе нужен, либо выдери кусок из исходников QDir. Там вроде используется QRegExp.


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 14, 2012, 23:39
Добавил такую же RegExp проверку как и внутри QDir. Результат как и ожидалось при одном цикле быстрее.
Я думаю уже стоит отметить тему как решенную =).


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 15, 2012, 00:09
Добавил такую же RegExp проверку как и внутри QDir. Результат как и ожидалось при одном цикле быстрее.
Я думаю уже стоит отметить тему как решенную =).
подробнее пожалуйста куда регулярные выражения вставлять?

попробуй поменять местами поиск, сначала с одним циклом, потом с двумя))) посмотри у себя, бывают чудеса

я заметил, что тот алгоритм, который первым ищет - теряет во времени!!!!

нужно независимо их запускать, я в плане не по очереди, а один алгоритм в приложении и так смотреть


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 15, 2012, 00:17
подробнее пожалуйста куда регулярные выражения вставлять?

попробуй поменять местами поиск, сначала с одним циклом, потом с двумя))) посмотри у себя, бывают чудеса

я заметил, что тот алгоритм, который первым ищет - теряет во времени!!!!

нужно не зависимо их запускать, я в плане не по очереди, а один алгоритм в приложении и так смотреть
Менял я поиск местами, как видишь дошел до отдельных кнопок. После нескольких нажатий уже вроде как мож что кешируется или типа того. Но все-равно с одним циклом побыстрее =). Хотя да иногда бывают странности ибо это ФС это такая штука... Вот если подключить RAM диск и на нем проводить замеры, тогда да будет точные данные.

Насчет регулярок я сделал вот так(мог что-то и не так сделать, у меня по вечерам уже голова не так хорошо работает):
Код
C++ (Qt)
void FindFiles::find2(QString pathr, QStringList filters)
{
   qint64 start;
   qint64 stop;
   start = QDateTime::currentMSecsSinceEpoch();
   QVector<QRegExp> regFilters;
   regFilters.reserve(filters.size());
   if (!filters.isEmpty() && !filters.contains("*")) {
       for (qint32 i=0; i<filters.count(); i++) {
           QRegExp regFilter(filters.at(i), Qt::CaseInsensitive, QRegExp::Wildcard);
           regFilter.setMinimal(true);
           regFilters.append(regFilter);
       }
   }
 
   QStack<QString> dirs;
   QString path;
   QStringList *listFiles = new QStringList;
   if(pathr.isEmpty())
       path = QDir::currentPath();
   else
       path = pathr;
   dirs.push(path);
   while (!dirs.isEmpty()) {
       path = dirs.pop();
       QDir dir(path);
 
       if(!dir.exists())
           continue;
 
       foreach (QFileInfo file, dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) {
           if(file.isDir()) {
               dirs.push(file.absoluteFilePath());
           } else {
               if (regFilters.isEmpty()) {
                   *listFiles << file.absoluteFilePath();
               } else {
                   for (qint32 i=0; i<regFilters.count(); i++) {
                       if (regFilters.at(i).exactMatch(file.fileName())) {
                           *listFiles << file.absoluteFilePath();
                           break;
                       }
                   }
               }
           }
       }
   }
   stop = QDateTime::currentMSecsSinceEpoch();
   emit finded2(listFiles, stop-start);
}


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 15, 2012, 00:33
вот просто по очереди перекомпилил, менял очередность вызова алгоритмов и вот, что у меня

и получается при любом варианте, выигрывают 2 цикла (может комп у меня особенный)

хоть, когда первым стартует, хоть вторым, соответственно выигрывает одному циклу при разной очередности его вызова


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 15, 2012, 00:40
подробнее пожалуйста куда регулярные выражения вставлять?

попробуй поменять местами поиск, сначала с одним циклом, потом с двумя))) посмотри у себя, бывают чудеса

я заметил, что тот алгоритм, который первым ищет - теряет во времени!!!!

нужно не зависимо их запускать, я в плане не по очереди, а один алгоритм в приложении и так смотреть
Менял я поиск местами, как видишь дошел до отдельных кнопок. После нескольких нажатий уже вроде как мож что кешируется или типа того. Но все-равно с одним циклом побыстрее =). Хотя да иногда бывают странности ибо это ФС это такая штука... Вот если подключить RAM диск и на нем проводить замеры, тогда да будет точные данные.

Насчет регулярок я сделал вот так(мог что-то и не так сделать, у меня по вечерам уже голова не так хорошо работает):
Код
C++ (Qt)
void FindFiles::find2(QString pathr, QStringList filters)
{
   qint64 start;
   qint64 stop;
   start = QDateTime::currentMSecsSinceEpoch();
   QVector<QRegExp> regFilters;
   regFilters.reserve(filters.size());
   if (!filters.isEmpty() && !filters.contains("*")) {
       for (qint32 i=0; i<filters.count(); i++) {
           QRegExp regFilter(filters.at(i), Qt::CaseInsensitive, QRegExp::Wildcard);
           regFilter.setMinimal(true);
           regFilters.append(regFilter);
       }
   }
 
   QStack<QString> dirs;
   QString path;
   QStringList *listFiles = new QStringList;
   if(pathr.isEmpty())
       path = QDir::currentPath();
   else
       path = pathr;
   dirs.push(path);
   while (!dirs.isEmpty()) {
       path = dirs.pop();
       QDir dir(path);
 
       if(!dir.exists())
           continue;
 
       foreach (QFileInfo file, dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) {
           if(file.isDir()) {
               dirs.push(file.absoluteFilePath());
           } else {
               if (regFilters.isEmpty()) {
                   *listFiles << file.absoluteFilePath();
               } else {
                   for (qint32 i=0; i<regFilters.count(); i++) {
                       if (regFilters.at(i).exactMatch(file.fileName())) {
                           *listFiles << file.absoluteFilePath();
                           break;
                       }
                   }
               }
           }
       }
   }
   stop = QDateTime::currentMSecsSinceEpoch();
   emit finded2(listFiles, stop-start);
}
сильно написано, просто думаю как раз из-за регулярных выражений и тормоза при одном цикле, чего бы так не делать?

Код
C++ (Qt)
foreach (QString file, dir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot))
{
if(m_stop) return listFiles;
QFileInfo temp(dir,file);
 
if(temp.isDir())
dirs.push(path + QDir::separator() + file);
 
else if(m_FilterNames.contains("*." + temp.suffix(), Qt::CaseInsensitive))
{
listFiles << QFileInfo(dir, file).absoluteFilePath();
m_countFiles++;
emit currentCountFiles(m_countFiles);
}
}


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 15, 2012, 00:43
сильно написано, просто думаю как раз из-за регулярных выражений и тормоза при одном цикле, чего бы так не делать?
А ты посмотри исходники QDir, если конкретнее то QDirIterator. Там именно так и сделано. Но ничего не мешает тебе сделать по своему. Если надо фильтровать по расширению то вообще проще юзать QStrings.endsWith(".h");.


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 15, 2012, 00:47
сильно написано, просто думаю как раз из-за регулярных выражений и тормоза при одном цикле, чего бы так не делать?
А ты посмотри исходники QDir, если конкретнее то QDirIterator. Там именно так и сделано. Но ничего не мешает тебе сделать по своему. Если надо фильтровать по расширению то вообще проще юзать QStrings.endsWith(".h");.

ничего против не имею))) накрутка циклов при регулярных выражениях возрастает в разы, следовательно нечитабельно

а сейчас потестю у себя регулярные выражения

интересные данные, теперь, если вторым номером идёт один цикл, то он работает быстрее второго номера 2 циклов, ну и соответственно также, если первым номером))

но всё равно пока тот, кто стартует проигрывает второму номеру


Название: Re: Остановка рекурсии поиска файлов
Отправлено: V1KT0P от Март 15, 2012, 01:20
ничего против не имею))) накрутка циклов при регулярных выражениях возрастает в разы, следовательно нечитабельно
Щас провел замеры. Регулярка получается в 2 раза медленнее того что ты предлагаешь. Но в то-же время регулярка более гибкая. Если регулярка занимала 27% всего времени, то твой поиск 13%.


Название: Re: Остановка рекурсии поиска файлов
Отправлено: daimon от Март 15, 2012, 01:26
ничего против не имею))) накрутка циклов при регулярных выражениях возрастает в разы, следовательно нечитабельно
Щас провел замеры. Регулярка получается в 2 раза медленнее того что ты предлагаешь. Но в то-же время регулярка более гибкая. Если регулярка занимала 27% всего времени, то твой поиск 13%.

ну то понятно))) и тут сразу приходит на ум, что работает регулярка почти как 2 цикла (ведь там тоже есть фильтр)