На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> Фильтрация файлов в директории по расширению
    В коде:
    ExpandedWrap disabled
      static size_t CreateVectorsFiles(vector<string>& vsFullname, vector<string>& vsFilename, const char* dir, const char* ext)
      {
        for (const fs::directory_entry& dir_entry : fs::recursive_directory_iterator(dir))
        {
          if (fs::is_regular_file(dir_entry))
          {
            if (fs::path(dir_entry).extension() == ext)
            {
              vsFullname.push_back(dir_entry.path().string());
              vsFilename.push_back(fs::path(dir_entry).stem().string());
            }
          }
        }
        return vsFilename.size();
      }
       
      int main(int argc, char* argv[])
      {
        setlocale(LC_ALL, "Russian");
        for (int i = 0; i < argc; ++i)
          cout << argv[i] << endl;
        if (argc < 4)
          DisplayMessage("\nНе указаны параметры программы - директория для обработки, директория для результатов обработки и расширение файлов!\n", false);
        struct stat sb;
        if (stat(argv[1], &sb) != 0)
          DisplayMessage("\nДиректория для обработки не существует!\n", false);
        if (stat(argv[2], &sb) != 0)
          DisplayMessage("\nДиректория для записи результатов не существует!\n", false);
        vector<string> vsFullname, vsFilename;
        if (CreateVectorsFiles(vsFullname, vsFilename, argv[1], argv[3]) == 0)
          DisplayMessage("\nДиректория для обработки не содержит файлов с заданным расширением!\n", false);
        if (!fs::is_empty(argv[2]))
          DisplayMessage("\nВ директории для обработки есть файлы! Очистите директорию!\n", false);
        system("pause");
      }
    получаю сообщение, что директория не содержит файлов с заданным расширением. Параметры отладки следующие:
    ExpandedWrap disabled
      "D:\TestProgramsDir" "D:\TestProgramsDir\Res" "*.txt"
    В первой директории (1 параметр) есть несколько поддиректорий с файлами с расширением txt. Проект и тестовую директорию прикрепил. Помогите, пожалуйста, исправить ошибку.
    Прикреплённый файлПрикреплённый файлTestProgramsDir.zip (3,73 Кбайт, скачиваний: 31)
    Прикреплённый файлПрикреплённый файлcppProcFiles.zip (2,78 Кбайт, скачиваний: 30)
      Ну, не вполне очевидно, конечно, но всё ж на поверхности: ты под ext передаёшь argv[3], который задаёшь маской, тогда как std::filesystem::path::extension() возвращает именно что расширение. Неудивительно, что .txt не совпадает с *.txt

      Добавлено
      P.S. А почему stat()? Почему не std::filesystem::is_directory()?
        Не знал об std::filesystem::is_directory(), теперь буду использовать. Заменил "*.txt" на "txt" - результат тот же
          .txt

          Добавлено
          Вообще, мы привыкли, что наборы файлов задаются маской. Я не знаю, что у тебя за задача, но предположу, что будет лучше фильтровать как раз маской, а не расширением. Даже если расширения достаточно, просто маской привычнее. К сожалению, std::filesystem::directory_iterator (и его рекурсивный аналог) не умеют маски, что с моей точки зрения является недочётом. Так что фильтровать нужно будет руками. Я бы предложил <regex>:
          ExpandedWrap disabled
              std::string wildMask(ext);
             
              for (auto i = 0; i < wildMask.length(); ++i)
                if      (wildMask[i] == '.') wildMask.replace(i++, 1, "\\.");
                else if (wildMask[i] == '*') wildMask.replace(i++, 1, ".*?"), ++i;
                else if (wildMask[i] == '?') wildMask[i] = '.';
             
              std::regex mask(wildMask);
            /* ... */
              if (std::regex_match(dir_entry.path().filename().string(), mask))
            /* ...*/


          Добавлено
          Но есть нюанс: учитывается регистр. Под POSIX пофигу, но в винде это важно. Сделать поиск регистронезависимым можно в конструкторе std::regex:
          ExpandedWrap disabled
            std::regex mask(wildMask, std::regex_constants::icase);
          Сообщение отредактировано: Qraizer -
            Спасибо большое, все отлично работает. Но все-таки хотелось бы узнать, как без маски выбирать все файлы в строке
            ExpandedWrap disabled
              if (fs::path(dir_entry).extension() == ext)
            . Каким должен быть exp? Пробовал "*", ".", " " - не получилось. Буду также изучать работу с регулярными выражениями, плохо понимаю, как они работают и создаются маски (раньше regex не использовал, хотя и понимал, что это штука очень нужная).
              Цитата tumanovalex @
              Каким должен быть exp?

              Глянь тут, там в разделе Example есть пример, не требующий объяснений.
                Видимо, это для умных объяснений не надо. А я не разобрался.
                  Цитата tumanovalex @
                  А я не разобрался.

                  Перевод описания:

                  Цитата
                  std::filesystem::path::extension

                  Возвращает расширение компонента filename generic-формата пути *this.

                  Если компонент filename() пути общего формата содержит точку (.) и не является одним из специальных элементов файловой системы dot или dot-dot, то расширением является подстрока, начинающаяся с крайней правой точки (включая точку) и до конца имени пути.

                  Если первым символом в имени файла является точка, то эта точка игнорируется (имя файла типа ".profile" не рассматривается как расширение).

                  Если имя пути содержит либо ., либо ..., либо если filename() не содержит символа '.', то возвращается пустой путь.

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

                  Переведено с помощью www.DeepL.com/Translator (бесплатная версия)

                  Напиши, что именно тебе не понятно.
                    Мне не понятно, каким должна быть переменная ext, чтобы вектора формировались из файлов с любыми расширениями. Если я указываю ".txt" или ".pdf", то вектора формируются из файлов с указанными расширениями.
                    Код Qraizer позволяет считывать как файлы с определенным расширением, так и все файлы в заданной директории. Причем отбора по признаку
                    ExpandedWrap disabled
                      fs::is_regular_file(dir_entry)
                    , как я понял, не требуется. Как ему это удалось - я пока не разобрался. Но все-таки хотелось бы узнать, что нужно присвоить переменной ext, чтобы через фильтр
                    ExpandedWrap disabled
                      if (fs::path(dir_entry).extension() == ext)
                    проходили все файлы, с любым расширением (чтобы убедиться, что это возможно или нет). Я уже попробовал несколько вариантов - ни один из них не прошел.
                      Цитата tumanovalex @
                      Каким должен быть exp? Пробовал "*", ".", " " - не получилось.

                      Ответ простой - надо отлаживать программу.
                      Методом тыка много не наработаешь.
                      Ты строки сравниваешь тут ?:
                      ExpandedWrap disabled
                        if (fs::path(dir_entry).extension() == ext)

                      Перед сравнением выводи строки - да хоть printf-ом.
                        Цитата ЫукпШ @
                        Перед сравнением выводи строки - да хоть printf-ом.

                        Не понял, как это мне поможет. Я уже пробовал - extension() выводит расширение файла (".txt", ".pdf", ".cpp" и др.). Как я понял, код Qraizer сравнивает расширение с возможными комбинациями символов и если расширение есть в этой комбинации - то пропускает определенное расширение или же пропускает все расширения. Как я понял, фильтр с "== ext" сработает только для конкретного расширения и не срабатывает для всех файлов. Т.е. нельзя задать строку для exp, которая позволила бы пропускать файлы с любым расширением. Поэтому остается либо использовать этот фильтр только для конкретных расширений, либо в общем случае использовать код Qraizer.
                          Цитата tumanovalex @
                          Мне не понятно, каким должна быть переменная ext, чтобы вектора формировались из файлов с любыми расширениями.

                          У тебя изначально неверный подход к формулировке задачи ... Смотри аналогию: "Какой должна быть переменная int, чтобы она соответствовала любому значению?". Обычно так не бывает, и не может быть.
                          Но хорошее решение есть - задавать переменную маской в виде регулярного выражения. И файлы искать не по "расширению" а по "маске". Выше Qraizer начал развивать эту мысль, но ты на это обратил недостаточно внимания, коль пытаешься решить своим изначально неправильным решением.
                            Да я обратил внимание. Код проверил, отлично работает для конкретных и всех расширений. Действительно, что-то у меня в понятиях сбилось - сравниваю конкретной расширение с шаблоном и при этом хочу, чтобы фильтровались все расширения. Так что прошу прощения за навязанную глупую дискуссию.
                              Цитата tumanovalex @
                              при этом хочу, чтобы фильтровались все расширения

                              Ну вот пример регулярки, которая одна фильтрует (ловит) файлы с пятью расширениями. Можно регулярку усложнить. Можно наоборот писать простые регулярки, но чекать в цикле набор регулярок. Основная идея - на привязываться к расширению файла, как к таковому, а использовать маску или маски файлов.
                                Спасибо, буду разбираться.
                                  Регулярки – штука довольно интересная. И востребована, не даром их поддержка есть во многих языках. (А некоторые так на них вообще и основаны даже. Да, Majestio ;) ?) Для твоей задачи преобразования маски в регулярку достаточно знать, что:
                                  • . означает любой символ;
                                  • * означает, что предшествующий символ или группа повторяется произвольное количество раз, возможно 0; в некоторых грамматиках захватывает максимально возможное количество (т.н. жадное сопоставление);
                                  • ? означает, что предшествующий символ * превращается в нежадный, т.е. захватывает наивозможный минимум раз;
                                  • \ означает, что следующий символ распознаётся как обычный, а не командный;
                                  • остальные... ну как остальные, кроме командных, их больше, чем я тут перечислил... символы сопоставляются в точности, как указаны.
                                  Т.е. маска, скажем FileTxt?2.* должна быть преобразована в регулярку FileTxt.2\..*?, где красный суть любой одиночный символ, оранжевый означает просто символ ., а не командный . (т.е. не обозначает любой символ), а синий означает нежадное (в маске * работает именно нежадно) количество любых символов.
                                  Но естественно у регулярок куда больше возможностей. Так что я бы рекомендовал ими позаниматься.

                                  Добавлено
                                  P.S. Маске *.* будет соответствовать .*?\..*? :D
                                  Сообщение отредактировано: Qraizer -
                                    Цитата Qraizer @
                                    (А некоторые так на них вообще и основаны даже. Да, Majestio ?)

                                    На Перл намёкиваешь? :lol: Да, в Перле регулярки являются частью языка. Это его отличает от других ЯП, в которых регулярки используются в виде подключаемых библиотек.
                                      Цитата Majestio @
                                      Перл

                                      :wub:

                                      Добавлено
                                      Цитата Majestio @
                                      Это его отличает от других ЯП, в которых регулярки используются в виде подключаемых библиотек.

                                      Даёшь pcre в каждый ЯП :lol:
                                      0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                      0 пользователей:


                                      Рейтинг@Mail.ru
                                      [ Script execution time: 0,0484 ]   [ 18 queries used ]   [ Generated: 27.04.24, 10:44 GMT ]