Ir ao conteúdo
  • Cadastre-se
Cortella

C++ Ler varios arquivos Simultaneamente

Posts recomendados

Ola, estou com um trabalho de faculdade no qual preciso ler 12000 arquivos, gostaria de saber se existe alguma funcao que le todos os arquivos de uma pasta!!

 

Obrigado

  • Curtir 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

você pode usar a biblioteca <dirent.h> para obter todos os nomes de arquivos de um diretório:

#include <dirent.h>
#include <stdio.h>
 
int main()
{
    DIR *d;
    struct dirent *dir;
    d = opendir("."); //diretório atual;
    if (d != NULL)
    {
        while ((dir = readdir(d)) != NULL) //lsita todos os arquivos do diretorio
        {
            printf("%s\n", dir->d_name); 
            FILE * pFile;
            pFile = fopen (dir->d_name,"r"); //abre o arquivo
            if (pFile!=NULL)
            {
               // insira aqui o codigo que manipula o arquivo
                fclose (pFile);
            }
        }
          closedir(d);
    }
    return 0;
}

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

No C++ tem a biblioteca <filesystem> a partir da versão C++17 da linguagem:

https://en.cppreference.com/w/cpp/header/filesystem

 

Fiz um programa exemplo:

#include <iostream>
#include <string>
#include <fstream>
#include <filesystem>
namespace fs = std::filesystem;
 
int main()
{
    std::string data;
    fs::create_directories("sandbox/a/b"); //cria subdiretórios sandbox/a/b no diretório atual
    std::ofstream file1("sandbox/file1.txt"); //cria arquivo no diretório sandbox
    std::ofstream file2("sandbox/file2.txt"); //cria arquivo no diretório sandbox
    file1 << "123";
    file2 << "ABC";
    file1.close();
    file2.close();
    for(auto& p: fs::directory_iterator("sandbox")){ //itera nos arquivos e subdiretórios do sandbox
        std::cout << p << '\n';
        if(fs::is_regular_file(p)){ //Se for um arquivo
            std::ifstream(p.path()) >> data; //lê o conteúdo do arquivo
            std::cout << data << "\n"; //imprime o conteúdo
        }
        std::cout << std::endl;
    }
    fs::remove_all("sandbox"); //deleta todos o diretório sandbox e seus arquivos e subdiretórios
    return 0;
}

 

Mas precisa usar um compilador recente que disponibilize os recursos da versão C++17 ou mais recente da linguagem C++, e compilar usando a flag para essas versões (-std=c++17, -std=gnu++17, -std=c++2a ou -std=gnu++2a).

 

 

Na versão C++14 filesystem estava disponível como experimental (#include <experimental/filesystem>), e para versões antes disso seria necessário usar a biblioteca não padrão Boost.

  • Curtir 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

Olá!

 

Não estou certo de que queira ler 12000 arquivos simultaneamente se eles estão na mesma pasta. Vou imaginar que queira ler sequencialmente, afinal estão todos no mesmo disco e na mesma pasta.

 

Como @Flávio Pedroza disse, dirent é uma opção. Tem mais de vinte anos, roda em várias plataformas e é código aberto. O arquivo único dirent.h tem 23K apenas e pode ser copiado de https://github.com/tronkko/dirent.

 

Usar a biblioteca boost ou sua versão com roupa nova <filesystem> é uma opção se estiver usando C++ em Windows, como sugeriu @isrnick 

 

Acredito o mais compatível com várias versões de windows e compiladores seria usar FindFirstFile, FindNextFile e FindClose, como descrito pelo dono do campo, da bola e das camisas em http://docs.microsoft.com. Pode ver aqui um exemplo da Microsoft de como listar os arquivos de um diretório, de maio de 2018... Serviria  para seu caso também

 

Eu ficaria com o mais portável e simples dirent...

Veja um exemplo usando dirent:

Supondo  que: 

você tem umas funções que fazem algo com um arquivo 'a', como ler ou imprimir informações sobre 'a', 
e quer chamar estas funções para todos os arquivos comuns na pasta 'p'.

E você gostaria de chamar uma mágica função assim:

executa_na_pasta(pasta, faz_o_servico_1)  ou
executa_na_pasta(pasta, faz_o_servico_2) 

para rodar 
    faz_o_servico_1(p) ou 
    faz_o_servico_2(p) 
na pasta 'p'

Vamos imaginar que a função 1 seja bem simples, apenas liste na tela o nome do arquivo, e a função 2 liste na tela o nome e o tamanho do arquivo em bytes, e as duas retornem um long, irrelevante no caso da primeira ou com o tamanho do arquivo no caso da segunda. Assim usando a segunda você pode ir somando o total de bytes ocupados pelos arquivos na pasta

 

Para uma pasta assim

 

190606-lista-pasta.png.0f34ee135df76fe8dad328a5a898ecee.png

 

A saída dese programa seria assim

 

190606-saida-programa.png.4cffcf20ba77068e977cf143ae44f61c.png

 

E isso serve de exemplo para o que você precisa fazer. Eis uma possível função 1, que só imprime o nome do arquivo, bem besta

long faz_o_servico_1(const char * arquivo)
{
    printf("%s\n", arquivo);
    return 0;
}

Eis uma possível função 2, que imprime também o tamanho, como suposto no exemplo

long faz_o_servico_2(const char * arquivo)
{
    struct stat fileInfo;
    int r = stat(arquivo, &fileInfo);
    printf(
        "%-40s\t%8d\n",
        arquivo, fileInfo.st_size
    );
    return fileInfo.st_size;
}

Você chamaria essa função de que precisa assim:

    printf("\n--------------------------------------------------\n");
    printf("\ntesta com a funcao 1\n");
    executa_na_pasta(pasta_local, faz_o_servico_1);
    printf("\n--------------------------------------------------\n");
    printf("\ntesta com a funcao 2\n");
    executa_na_pasta(pasta_local, faz_o_servico_2);

E ela rodaria a função indicada na sua pasta com 5 ou 12.000 arquivos. Para qualquer função que você escreva desde que retorne int ou long, certo? 

 

Eis uma possível implementação de executa_na_pasta(), que funciona em Windows. Para Linux ou MAC acho que precisa só mudar o separador de \ para / porque eu não me preocupei com portabilidade afinal, nada mais

long executa_na_pasta(const char * pasta, long(*a_funcao)(const char *))
{
	// roda a funcao a_funcao() para todos os arquivos na
	// pasta 'pasta' e retorna o total em bytes da soma do
	// tamanho dos arquivos
	struct dirent *diretorio;		// descreve o diretorio
	DIR *pDir = opendir(pasta);		// o ponteiro para o diretorio
	char * nome_completo;			// nome do arquivo na pasta
	long total = 0;					// para somar os tamanhos
	printf("\n[%s]\n\n", pasta);
	if (pDir == NULL)
	{
		printf("Erro ao abrir %s\n", pasta);
		return(-1);
	}	// end if
	while ((diretorio = readdir(pDir)) != NULL)
	{
		// em d->name esta o nome do arquivo
		// entao precisamos da string 'pasta\nome'
		// para ver se e um arquivo comum e listar afinal
		int n = 2 + strlen(pasta) + strlen(diretorio->d_name);
		nome_completo = (char *)malloc((size_t)n);
		// monta o nome do arquivo: pasta \ nome no windows
		sprintf_s(nome_completo, n, "%s\\%s", pasta, diretorio->d_name);
		// se for um arquivo comum, chama a funcao

		//   faz o servico para cada arquivo na pasta     ***********************
		if (eh_um_arquivo(nome_completo)) total = total + a_funcao(nome_completo);
		//                                                ***********************
		free(nome_completo);	// libera o nome
	}	// end while
	printf("\nTotal de %d bytes nos arquivos da pasta\n", total);
	closedir(pDir);	//	ao sair fecha a pasta
	return(0);
}	// end executa_na_pasta()

Só isso. O trabalho mesmo está em uma linha só, entre os comentários com ***************** onde chama 

        if (eh_um_arquivo(nome_completo)) total = total + a_funcao(nome_completo);

a função eh_um_arquivo() recebe o nome do arquivo, que é pasta\arquivo no Windows e retorna 1 se é um arquivo comum, só para ficar fácil de ler o programa. Pra não faltar nada:

int eh_um_arquivo(const char * nome)
{
    int r;
    struct stat fileInfo;
    r = stat(nome, &fileInfo);
    if ((r == 0) && (S_ISREG(fileInfo.st_mode))) return (1);
    return(0);
}    // end eh_um_arquivo()

É isso. Fim do exemplo. Pode escrever sua rotina de serviço e vai rodar de imediato com esse código. Veja de novo a saída do programa lá em cima e se não entendeu escreva de novo

 

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

Gostaria de agradecer de coracao a ajuda de todos em especial a de@arfneto ...

Tentei utilizar a biblioteca,porém me deparei com o seguinte erro:

 

C:\Cortella\Projetos\Trabalho_PDS\Buscador>g++ Buscador.cpp
In file included from Buscador.cpp:5:0:
dirent.h:383:28: error: missing binary operator before token "("
 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
                            ^
dirent.h:405:28: error: missing binary operator before token "("
 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
                            ^
dirent.h: In function '_WDIR* _wopendir(const wchar_t*)':
dirent.h:413:43: error: 'wcsncpy_s' was not declared in this scope
     wcsncpy_s (dirp->patt, n+1, dirname, n);
                                           ^

 

Gostaria de saber se o erro em questão se trata de uma incompatibilidade em meu sistema: segue meu codico em anexo ...

#include <iostream>
#include "dirent.h"

using namespace std;

int main(int argc, char* argv[]) {

	DIR* d;
	struct dirent* dir;
	d = opendir(".data"); //diretório atual;
	if (d != NULL) {
		//le todos os arquivos no diretorio especificado
		while ((dir = readdir(d)) != NULL) {
			//cout << "\n " << dir->d_name << endl;
			char namePaste[50] = "./data/";
			int aux;

			//Copia nome das pastas do diretorio
			for (int i = 0; i < dir->d_namlen; i++) {
				aux = (int)dir->d_name[i];
				//seleciona caracteres a partir de ASCII
				if ((aux >= 97 && aux <= 122) || (aux >= 48 && aux <= 57) || (aux == 45) || (aux == 46)) {
					namePaste[i+7] = dir->d_name[i];
					//Cria novo diretorio para entrar na pasta
					DIR* p;
					struct dirent* paste;
					//Abre Pasta
					p = opendir(namePaste);
					if (p != NULL) {
						while ((paste = readdir(p)) != NULL) {
							cout << "\n " << paste->d_name;
						}
					}
				}

			}

		}
	}
	return 0;
}

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

A biblioteca dirent.h não está corretamente instalada no seu compilador.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisar ser um membro para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora





Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas publicações sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

GRÁTIS: minicurso “Como ganhar dinheiro montando computadores”

Gabriel TorresGabriel Torres, fundador e editor executivo do Clube do Hardware, acaba de lançar um minicurso totalmente gratuito: "Como ganhar dinheiro montando computadores".

Você aprenderá sobre o quanto pode ganhar, como cobrar, como lidar com a concorrência, como se tornar um profissional altamente qualificado e muito mais!

Inscreva-se agora!