Discussion:
listado recursivo
(demasiado antiguo para responder)
Cachorro
2006-03-07 16:10:36 UTC
Permalink
Hola buenas a todos.
Escribí este programa que lista recursivamente ficheros y directorios, o al
menos eso es lo que se intenta, alguna ayudita de donde puede estar el
fallo :).

Muchas gracias y un saludo Cachorro

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


const int MAXPATHLEN=1024;
///#include <pme.h> expresiones regulares

void rDir(char *ruta){
DIR *cDir;
struct dirent *entrada;
cDir=opendir(ruta);
//preparamos el nivel k
//mientras existen hijos
while((entrada=readdir(cDir))){
if((strcmp(entrada->d_name, "."))&&(strcmp(entrada->d_name, ".."))){
if(entrada->d_type!=DT_DIR){//fichero
printf ("\t%s%s\n",ruta, entrada->d_name);
}else{//directorio
if (ruta[strlen(ruta)-1]!='/'){
strcat (ruta, "/");
}
strcat (ruta, entrada->d_name);
printf ("[DIR]%s\n",entrada->d_name);
rDir(ruta);
printf ("Cerrando cdir\n");
closedir (cDir);
}
}

}


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

char *ruta=NULL;
printf ("%d", argc);
if (argc<2){
ruta=".";
}else{
ruta=argv[1];
}

printf ("Directorio de trabajo => [ %s ] \n", ruta );
printf ("LLamamos a la funcion rDir como parametro => %s\n", ruta);
rDir(ruta);

return 0;
}

SALIDA
===========================
2Directorio de trabajo => [ /home/arcangel ]
LLamamos a la funcion rDir como parametro => /home/arcangel
[DIR].kde
[DIR]share
[DIR]config
/home/arcangel/.kde/share/configkpgprc
/home/arcangel/.kde/share/configkonqsidebartng.rc
/home/arcangel/.kde/share/configkdeglobals
/home/arcangel/.kde/share/configkdedrc
/home/arcangel/.kde/share/configkconf_updaterc
/home/arcangel/.kde/share/configkickerrc
/home/arcangel/.kde/share/configkcookiejarrc
[DIR]session
/home/arcangel/.kde/share/config/sessionkcontrol_10d4cb9570000113923548900000049270016_1139304381_550682
/home/arcangel/.kde/share/config/sessionkonsole_10d4cb9570000113923507800000049270009_1139304381_532784
/home/arcangel/.kde/share/config/sessionkwin_10d4cb9570000113923488300000049270000_1139304381_573846
Cerrando cdir
/home/arcangel/.kde/share/config/session·yï·yï· yï· yï·šyï·šyï·°yï·°yï·žyï·žyï·Àyï·Àyï·Èyï·Èyï·Ðyï·Ðyï·Øyï·Øyï·àyï·àyï·èyï·èyï·ðyï·ðyï·øyï·øyï·
Cerrando cdir
/home/arcangel/.kde/share/config/session·ðxï·ðxï·øxï·øxï·
Cerrando cdir
/home/arcangel/.kde/share/config/session·ðxï·ðxï·øxï·øxï·
Cerrando cdir
/home/arcangel/.kde/share/config/session·èxï·ðxï·ðxï·øxï·øxï·
Pedro Maicas
2006-03-07 18:33:42 UTC
Permalink
Yo veo dos problemillas, consecuencia de ser una
funcion recursiva y de que el nombre de cada sudirectorio
se vaya añadiendo al final del nombre que recibe como parametro
para construir el path completo.

1.- Que la llamda primera a la funcion debe hacerse con
el nombre en un buffer de caracteres bastante grande para albergar
el path completo del nombre más largo que exista.

rDir("/"); //provocará una excepcion

char buffer[4096]="/";

rDir(buffer); //es lo correcto

2.- Que cuando "empalmas" el path con un nuevo nombre de directorio
debes recuperar luego el nombre antiguo, pues lo necesitas para usarlo
en el siguiente directorio.

n = strlen(path); //memoriza longitud de string
strcat(path, dirname); //empalma nombre subdirectorio
rDir(path); //usa el path completo
path[n] = 0; //deja el nombre como estaba.

Esto creo que era lo que querias hacer, y es lo que suelo
hacer yo, porque es lo más rápido y lo que menos memoria usa.
Post by Cachorro
void rDir(char *ruta){
DIR *cDir;
struct dirent *entrada;
cDir=opendir(ruta);
//preparamos el nivel k
//mientras existen hijos
while((entrada=readdir(cDir))){
if((strcmp(entrada->d_name, "."))&&(strcmp(entrada->d_name, ".."))){
if(entrada->d_type!=DT_DIR){//fichero
printf ("\t%s%s\n",ruta, entrada->d_name);
}else{//directorio
if (ruta[strlen(ruta)-1]!='/'){
strcat (ruta, "/");
}
strcat (ruta, entrada->d_name);
printf ("[DIR]%s\n",entrada->d_name);
rDir(ruta);
printf ("Cerrando cdir\n");
closedir (cDir);
}
}
}
Saludos :-) -Pedro-

http://www.maicas.net/

e-mail en www.maicas.net
Cachorro
2006-03-08 02:56:19 UTC
Permalink
Muchas gracias Pedro, parece q la cosa funciona, :S aunque no tengo mucha
seguridad de que cuando se ejecute el resultado es el correcto.

Dudas:
porque tengo q restaurar el nombre, (obiamente porque si no no va), pero no
encuentro el motivo.


Saludos Cachoro

======================================================
Funcion
======================================================
void rDir(char *ruta){
DIR *cDir;
struct dirent *entrada;
if ((cDir=opendir(ruta))){
while((entrada=readdir(cDir))){
if((strcmp(entrada->d_name, ".")) && (strcmp(entrada->d_name, ".."))
{//no nos interesan ni . ni ..
if(entrada->d_type!=DT_DIR){//fichero caso trivial
printf ("\t%s/%s\n",ruta, entrada->d_name);
}else{//directorio caso no trivial
int n = strlen(ruta); //memoriza longitud de string
strcat (ruta, "/");
strcat(ruta, entrada->d_name);//empalma nombre subdirectorio
printf ("[DIR] %s\n", ruta);
rDir(ruta); //llamada recursiva
ruta[n] = 0; //deja el nombre como estaba.
}
}

}
}
closedir(cDir);//cerramos el directorio
}
=========================================================
Bartomeu
2006-03-08 06:52:14 UTC
Permalink
Post by Cachorro
Muchas gracias Pedro, parece q la cosa funciona, :S aunque no tengo mucha
seguridad de que cuando se ejecute el resultado es el correcto.
porque tengo q restaurar el nombre, (obiamente porque si no no va), pero no
encuentro el motivo.
Si tienes un directorio con varios subdirectorios, una vez recorrido un
subdirectorio debes dejar el buffer como estaba para que al entrar en los
siguientes subdirectorios del mismo nivel la función trabaje exactamente
como la primera vez.

Ten en cuenta que estás utilizando el mismo buffer en todos los niveles de
recursividad (es una variable global), por lo tanto, cada función lo tiene
que dejar tal como lo encontró.

Si utilizaras memoria local en cada función, el trabajo ya te lo haría el
compilador llenando/vaciando la memoria local, pero sería más fácil que se
reventara la pila si utilizas muchos niveles de directorios y/o nombres muy
largos.
Post by Cachorro
Saludos Cachoro
Pedro Maicas
2006-03-08 22:59:28 UTC
Permalink
Post by Cachorro
porque tengo q restaurar el nombre, (obiamente porque si no no va), pero no
encuentro el motivo.
Pues porque lo modificas, y lo necesitas luego.

Si a la entrada tienes un path, y al recorrer
el directorio obtienes nombres de fichero, en cada
uno de ellos concatenas path y nombre, es evidente
el primero lo concatenas bien, pero cuando vayas a
concatenar el segundo tienes que haber quitado el primero.

Solo tienes que mirar el resultado de ese printf,
veras que el primero esta bien, pero el segundo ya
tiene el nombre mal.

Es que es tan evidente que no se cómo explicarlo :-)

Saludos :-) -Pedro-

http://www.maicas.net/

e-mail en www.maicas.net

J.A. Gutierrez
2006-03-08 09:06:21 UTC
Permalink
Cachorro <***@gmail.com> wrote:
: Hola buenas a todos.
: Escribí este programa que lista recursivamente ficheros y directorios, o al
: menos eso es lo que se intenta, alguna ayudita de donde puede estar el
: fallo :).

: Muchas gracias y un saludo Cachorro

: #include <errno.h>
: #include <dirent.h>

Primer problema potencial:
Dependiendo del sistema puede que tengas que usar
<dirent.h> o <sys/dir.h>

: #include <stdio.h>
: #include <string.h>


: const int MAXPATHLEN=1024;

Segundo: MAXPATHLEN normalmente ya esta definido.
Tipicamente, en <sys/param.h>; aunque en el caso de
windows, seria _MAX_PATH

: ///#include <pme.h> expresiones regulares

Usar comentarios tipo "//" en C no es lo mas recomendable,
si se desea hacer codigo portable.

: void rDir(char *ruta){
: DIR *cDir;
: struct dirent *entrada;

Si se usa <sys/dir.h>, la estructura es "direct"

: cDir=opendir(ruta);
: //preparamos el nivel k
: //mientras existen hijos
: while((entrada=readdir(cDir))){
: if((strcmp(entrada->d_name, "."))&&(strcmp(entrada->d_name, ".."))){
: if(entrada->d_type!=DT_DIR){//fichero

Puede que en linux la estructura dirent tenga un campo
d_type; pero no es lo mas normal. Si quieres hacer codigo
portable, verifica que ese campo esta disponible (_DIRENT_HAVE_D_TYPE)
y si no lo esta, haz "stat" sobre cada entrada y verifica el tipo.

: }else{//directorio
: if (ruta[strlen(ruta)-1]!='/'){
: strcat (ruta, "/");
: }
: strcat (ruta, entrada->d_name);
: printf ("[DIR]%s\n",entrada->d_name);
: rDir(ruta);

aunque pases "ruta" como argumento, no deja de ser una cadena
global. Por lo tanto si la modificas dentro de la funcion,
tambien la estas modificando fuera. Supongo que es un efecto
lateral no deseado.

: printf ("Cerrando cdir\n");
: closedir (cDir);
: }
: }
--
PGP and other useless info at \
http://webdiis.unizar.es/~spd/ \
finger://daphne.cps.unizar.es/spd \ Timeo Danaos et dona ferentes
ftp://ivo.cps.unizar.es/pub/ \ (Virgilio)
Loading...