Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

_Isis_

[Resolvido] [Tutorial] Trabalhando com diretórios

Recommended Posts

Utilizando a função scandir podemos ler o conteúdo de um diretório passado como argumento, além de ordenar a lista que armazena esse conteúdo e filtrar os nomes de acordo com um padrão. Para utilizar a função é necessário incluir dirent.h.

 

int scandir(const char *dir, struct dirent ***namelist, int(*filter)(const struct dirent *), int(*compar)(const struct dirent **, const struct dirent **));

Protótipo da função

 

 

O primeiro argumento é o nome do diretório a ser lido. Namelist é a lista que armazenará o conteúdo do diretório. Os dois últimos argumentos são ponteiros para funções, tratados mais tarde. Por enquanto vamos ficar no básico: ler e listar o conteúdo do diretório.

 

 

 #include <dirent.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[]) {

 if (argc != 2)
	 return 1;

 struct dirent **lista = (struct dirent **)malloc(sizeof(struct dirent *));
 if (lista == NULL)
	 return 2;

 int conteudo;
 if ((conteudo = scandir(argv[1], &lista, 0, NULL)) == -1) {
	 fprintf(stderr,"%m\n");
	 return 2;
 }

 puts("Imprimindo as entradas...");
 while(conteudo--)
	 printf("%s\n", lista[conteudo]->d_name);

 free(lista);
 lista = NULL;
 return 0;
}

 

 

scandir1qs0.th.png

 

 

Se a função scandir retornar um inteiro maior que -1, esse é o número de entradas selecionadas. Caso algo errado ocorra, retorna -1. O %m imprime a mensagem associada ao valor da variável errno (extensão Glibc).

 

Caso o argumento passado não seja um diretório, a mensagem "Not a directory" é exibida.

 

Podemos ordenar a lista de entradas utilizando as funções alphasort ou versionsort, passando seu nome no último argumento da função. A função alphasort utiliza a strcoll (C99) e a versionsort, strverscmp. Qual a diferença? Considere o seguinte diretório:

 

scandir2uq7.th.png

 

 

O comando ls também utiliza as duas funções (strcoll e strverscmp). Listando os arquivos com ls -l, temos que o arquivo jan10 vem após jan1. Se a listagem for feita utilizando ls -lv, a função utilizada é strverscmp.

 

 

scandir3ll5.th.png

 

scandir4dw2.th.png

 

 

#include <dirent.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

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

 if (argc != 2)
	 return 1;

 struct dirent **lista = (struct dirent **)malloc(sizeof(struct dirent *));
 if (lista == NULL)
	 return 2;

 int conteudo;
 if ((conteudo = scandir(argv[1], &lista, 0, versionsort)) == -1) {
	 fprintf(stderr,"%m\n");
	 return 2;
 }

 puts("Imprimindo as entradas...");
 while(conteudo--)
	 printf("%s\n", lista[conteudo]->d_name);

 free(lista);
 lista = NULL;
 return 0;
}

 

A linha para compilar o código é gcc scandir_3.c -D _GNU_SOURCE

 

scandir5wb9.th.png

 

Repare que a listagem inclui ".." (diretório pai) e "." (diretório atual). Podemos retirar essas linhas utilizando um filtro, o terceiro argumento de scandir.

 

Aqui, precisamos conhecer os campos da estrutura dirent.

 

struct dirent {

ino_t d_ino;

off_t d_off;

unsigned short d_reclen;

unsigned char d_type;

char d_name[256];

};

 

O campo que vamos usar é d_name, que contém o nome do arquivo.

 

 #include <dirent.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int filtro(const struct dirent *F) {
 if (!strcmp(F->d_name,"..") || !strcmp(F->d_name,"."))
	 return 0;
 return 1;
}

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

 if (argc != 2)
	 return 1;

 struct dirent **lista = (struct dirent **)malloc(sizeof(struct dirent *));
 if (lista == NULL)
	 return 2;

 int conteudo;
 if ((conteudo = scandir(argv[1], &lista, filtro, versionsort)) == -1) {
	 fprintf(stderr,"%m\n");
	 return 2;
 }

 puts("Imprimindo as entradas...");
 while(conteudo--)
	 printf("%s\n", lista[conteudo]->d_name);

 free(lista);
 lista = NULL;
 return 0;
}

 

scandir6di3.th.png

 

Utilizando o campo d_type filtramos a listagem por tipo de arquivo.Criando diretórios, links simbólicos, sockets e executando o filtro p/ não exibir diretórios, temos:

 

scandir7rz5.th.png

 

scandir8gh6.th.png

 

int filtro(const struct dirent *F) {

 if (!strcmp(F->d_name,"..") || !strcmp(F->d_name,".") || F->d_type == DT_DIR )
	 return 0;
 return 1;
}

 

d_type só está definido para arquivos regulares, diretórios, FIFO (ou pipe), socket UNIX e dispositivos de bloco e caractere. Se tentarmos filtrar links simbólicos ou hardlinks utilizando DT_UNKNOWN, o código não funciona.

 

scandir8wt4.th.png

 

scandir9ft4.th.png

 

Nesse caso temos que usar o lstat e isso é um trabalho a mais, pois temos que ler sobre as macros de verificação de tipo de arquivo na manpage da função.

 

char * base;
int filtro(const struct dirent *F) {
struct stat info;
char * absolute_path = (char*)malloc(strlen(base)+strlen(F->d_name));
if (absolute_path == NULL)
   return 0;

memcpy(absolute_path, base, strlen(base));
memcpy(absolute_path+strlen(base), F->d_name,strlen(F->d_name));
absolute_path[strlen(base)+strlen(F->d_name)] = '\0';
int retorno = lstat(absolute_path, &info);

free(absolute_path);
absolute_path = NULL;

if (!strcmp(F->d_name,"..") || !strcmp(F->d_name,"."))
	return 0;
	if (!retorno && S_ISLNK(info.st_mode) || retorno == -1)
	return 0;
return 1;
}

 

A função lstat retorna 0 se não ocorrer nenhum erro. Liberamos a memória em seguida e o segundo if realiza a comparação do campo st_mode (que indica o tipo do arquivo) apenas se lstat tiver retornado 0. Então, se o arquivo não for "..", "." e nem um link simbólico, ele é incluido na listagem do diretório. Se o retorno de lstat for -1, a expressão do segundo if recebe 1 tornando-se verdadeira e não incluímos o nome que gerou o erro na lista.

 

scandir10aa8.th.png

 

Para retirar os hardlinks o processo é semelhante. A diferença é que o campo st_mode é identificado como um arquivo regular, então temos que contar o número de hardlinks, que, no caso de um hardlink será sempre maior que 1 (um arquivo regular possui apenas 1 hardlink).

 

int filtro(const struct dirent *F) {
struct stat info;
char * absolute_path = (char*)malloc(strlen(base)+strlen(F->d_name));
if (absolute_path == NULL)
   return 0;

memcpy(absolute_path, base, strlen(base));
memcpy(absolute_path+strlen(base), F->d_name,strlen(F->d_name));
absolute_path[strlen(base)+strlen(F->d_name)] = '\0';
int retorno = lstat(absolute_path, &info);

free(absolute_path);
absolute_path = NULL;

if (!strcmp(F->d_name,"..") || !strcmp(F->d_name,"."))
	return 0;

if (!retorno && (S_ISLNK(info.st_mode) || info.st_nlink > 1) || retorno == -1)
	return 0;
return 1;
}

 

scandir11bc5.th.png

 

#include <dirent.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>

char * base;
int filtro(const struct dirent *F) {
struct stat info;
char * absolute_path = (char*)malloc(strlen(base)+strlen(F->d_name));
if (absolute_path == NULL)
   return 0;

memcpy(absolute_path, base, strlen(base));
memcpy(absolute_path+strlen(base), F->d_name,strlen(F->d_name));
absolute_path[strlen(base)+strlen(F->d_name)] = '\0';
int retorno = lstat(absolute_path, &info);

free(absolute_path);
absolute_path = NULL;

if (!strcmp(F->d_name,"..") || !strcmp(F->d_name,"."))
	return 0;

if (!retorno && (S_ISLNK(info.st_mode) || info.st_nlink > 1) || retorno == -1)
	return 0;
return 1;
}

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

if (argc != 2)
	return 1;

struct dirent **lista = (struct dirent **)malloc(sizeof(struct dirent *));
if (lista == NULL)
	return 2;

int conteudo;
base = argv[1];
if ((conteudo = scandir(argv[1], &lista, filtro, versionsort)) == -1) {
	fprintf(stderr,"%m\n");
	return 2;
}

puts("Imprimindo as entradas...");
while(conteudo--)
	printf("%s\n", lista[conteudo]->d_name);

free(lista);
lista = NULL;

return 0;
}

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.