
Comumente quando estamos desenvolvendo nossas aplicações precisamos de tarefas corriqueiras para realizar o objetivo final do nosso projeto.
Uma das coisas mais frequentes, dentre outras, é listar arquivos de um diretório e geralmente recorremos a internet, no entanto, é muito simples de entender a lógica e fixarmos esse conceito para diminuirmos a perda de tempo realizando pesquisa.
Nessa dica rápida veremos como fazer isso de forma moderna com C++.
filesystemA biblioteca filesystem fornece recursos para executar operações em sistemas de arquivos e seus componentes, como caminhos, arquivos regulares e diretórios.
Ela foi originalmente desenvolvida pela Boost e na versão C++ 17 ela foi finalmente adotada pelo comitê para fazer parte da biblioteca padrão(STL).
Para usá-la incluiremos:
#include <filesystem>O namespace dela é muito grande, logo, é sempre interessante reduzir o caminho simplificando para fs somente, e isso é bom ser feito logo após a inclusão do cabeçalho:
namespace fs = std::filesystem;Se estiver usando um linter, pode ser que ele acuse o warning:
■ Namespace alias decl 'fs' is unused (fix available), isso é porque declaramos, mas ainda não usamos no nosso código, porém já já usaremos!
Agora vamos criar uma string que armazenará a pasta/diretório que queremos listar os arquivos(ex.: /path/to/directory), para esse exemplos listaremos o diretório atual mesmo:
std::string path = "./";E para listar os arquivos usaremos um Range-based for loop que também é carinhosamente confundido com for-each e percorremos nossa pasta utilizando um iterador nativo da filesystem que é o directory_iterator() e dentro do loop printaremos o elemento que nada mais é que o(s) arquivos do diretório, usando a função-mebro path():
Lembrando que se houver um subdiretório ele também listará.
for (const auto &entry : fs::directory_iterator(path)){
  std::cout << entry.path() << '\n';
}Após compilar normalmente e rodar, você notará os arquivos(e/ou diretórios, se houver) sendo listados.
Se quiser ter certeza que os arquivos estão sendo listado um de cada vez, você pode pausar a exibição com um sleep:
std::this_thread::sleep_for(std::chrono::seconds(1)); Nesse caso haverá um atraso de 1 segundo na exibição.
O código completo é:
#include <iostream>
#include <filesystem>
//#include <chrono>
//#include <thread>
namespace fs = std::filesystem;
int main(){
  std::string path = "./";
  for (const auto &entry : fs::directory_iterator(path)){
    std::cout << entry.path() << '\n';
    //std::this_thread::sleep_for(std::chrono::seconds(1)); 
  }
  return 0;
}A pausa está comentada!
Suponhamos que você tenham diversos arquivos assim: file1.jpg, file2.jpg,...file.10.jpg, ... file31.jpg, ao listar eles não aparecerão em ordem alfabética.
Para resolver isso, além de respeitar a ordem das dezenas, adicione os cabeçalhos:
#include <vector>
#include <algorithm>
#include <cctype> // isdigit
#include <sstream> // std::stringstreamCrie uma função com um lambda interna:
bool num_str_cmp(const fs::path& x, const fs::path& y) {
  auto get_number = [](const fs::path& path) {
    auto str_num = path.stem().string();
    std::string num_part {};
    for (char c : str_num) {
      if (std::isdigit(c)) {
        num_part += c;
      }
    }
    return !num_part.empty() ? std::stoi(num_part) : 0;
  };
  return get_number(x) < get_number(y);
}E agora ordene o vector com sort:
std::vector<fs::path> files_in_dir;
std::copy(fs::directory_iterator(path), fs::directory_iterator(), std::back_inserter(files_in_dir));
std::sort(files_in_dir.begin(), files_in_dir.end(), num_str_cmp);
for (const auto &entry : files_in_dir){
  std::cout << entry << '\n';
}Dessa forma resolveremos ambos os problemas: ordem alfabética e respeito das dezenas!
Código completo:
#include <iostream>
#include <filesystem>
#include <vector>
#include <algorithm>
#include <cctype> // isdigit
#include <sstream> // std::stringstream
namespace fs = std::filesystem;
bool num_str_cmp(const fs::path& x, const fs::path& y) {
  auto get_number = [](const fs::path& path) {
    auto str_num = path.stem().string();
    std::string num_part {};
    for (char c : str_num) {
      if (std::isdigit(c)) {
        num_part += c;
      }
    }
    return !num_part.empty() ? std::stoi(num_part) : 0;
  };
  return get_number(x) < get_number(y);
}
int main(){
  std::string path = "./imgs";
  std::vector<fs::path> files_in_dir;
  std::copy(fs::directory_iterator(path), fs::directory_iterator(), std::back_inserter(files_in_dir));
  std::sort(files_in_dir.begin(), files_in_dir.end(), num_str_cmp);
  for (const auto &entry : files_in_dir){
    std::cout << entry << '\n';
  }
  return 0;
}Para mais informações acesse: https://en.cppreference.com/w/cpp/filesystem.