Hallar directorios con espacios C

Iniciado por Tauron, 29 Mayo 2019, 18:27 PM

0 Miembros y 1 Visitante están viendo este tema.

Tauron

Hola buenas! Soy nuevo en el foro aunque ya lo he visitado muchas veces para distintos problemas.
La cuestion es que he escrito un codigo en C para poder eliminar los x primeros caracteres de todos los archivos encontrados en una ruta especifica.

El programa funciona con direcciones simples aunque no llega a ser muy robusto porque es para uso propio y me da bastante igual.
El problema ocurre cuando trato de poner (o arrastrar) una dirección que contiene espacios. No me reconoce la ruta y por lo tanto el programa es incapaz de listarme los archivos.
He probado insertando la ruta con comillas o sin, pero sin exito.
Si alguien encuentra el problema le estaré muy agradecido. No encuentro soluciones por la web.
(Apenas llevo meses programando. Solo se C y el tema de directorios y dirent.h no lo conocia)
Estoy en Windows con Dev-c++

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

#define MAXLONG 300

DIR *carpeta;
struct dirent *archivo; //struct propio de la libreria dirent.h. En archivo.d_name almacenará el nombre de archivo.

struct copia{
char nombre[MAXLONG];
};

int validar_ruta(char ruta[]);

void listar_dir(char ruta[], struct copia aux[], struct copia viejo[], int *cantidad);
void renombrar(char ruta[], struct copia aux[], struct copia viejo[],int *cantidad);
void guardar (char ruta[], struct copia aux[], struct copia viejo[], int *cantidad);
void mostrar(char ruta[]);


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

struct copia aux[MAXLONG], viejo[MAXLONG];
char ruta[MAXLONG];
int cantidad=0, repetir;

do{
repetir=0;
   system ("cls");
   printf("\n\n\t\t\t***** RENAMEADOR *****\n\n\n");
   printf("Arrastra la carpeta contenedora o escribe/pega la ruta\n\n");
   printf("DISCLAIMER: En caso de que los archivos no se hayan renombrado y el programa no muestre error\n\t    revisa las contrabarras '\\' en la direccion proporcionada...\n\n");
   printf("\n\nRuta de los archivos: "); gets(ruta);
if (validar_ruta(ruta)){
listar_dir(ruta,aux,viejo,&cantidad);
   renombrar(ruta,aux,viejo,&cantidad);
   guardar(ruta,aux,viejo,&cantidad);
   mostrar(ruta);
}
else repetir=1;
}while (repetir);
return 0;
};

int validar_ruta(char ruta[]){

int i;
char enter, aux;

carpeta = opendir(ruta);
if (carpeta == NULL){
printf("\nRuta a buscar: %s\n",ruta);
printf("\nEsta ruta no es valida !!\n");
printf("\n\n\nPress ENTER to retry..."); scanf("%c",&enter);
closedir(carpeta);
return 0;
}
else{
closedir(carpeta);
/*comprueba la ruta y añade un \ final si es necesario*/
while (ruta[i]!='\0'){
i++;
}
// printf("\n%c\n",ruta[i-1]); // ¿cual es el ultimo caracter?
if (ruta[i-1]!='\\'){ // si el ultimo caracter NO ES \, se lo añades.
strcat(ruta,"\\");
}
else return 1;
}
}

void listar_dir(char ruta[], struct copia aux[], struct copia viejo[], int *cantidad){
int i;
*cantidad=0;
   carpeta = opendir(ruta);

printf("\nRuta a buscar: %s\n",ruta);
   if (carpeta != NULL){ // verifica que la ruta sea valida
    printf("Archivos actuales:\n\n");
       while ((archivo = readdir(carpeta))){ // lee el directorio
       // puts (archivo->d_name);
        if (strcmp(archivo->d_name,".")){
        if (strcmp(archivo->d_name,"..")){
strcpy(aux[*cantidad].nombre,archivo->d_name); //copia al struct auxiliar la info que va recopilando el struct de dirent.h
        puts (aux[*cantidad].nombre);
        strcpy(viejo[*cantidad].nombre,aux[*cantidad].nombre); // copia el aux a uno viejo que en guardar sirve para el rename
*cantidad+=1; // auxiliar para saber cuántos archivos ha leido
    }
   }
}
}
   
   else
       perror ("\nError al abrir el directorio...  Existe?\n\n");
   closedir(carpeta);
}

void renombrar(char ruta[], struct copia aux[], struct copia viejo[], int *cantidad){
int i, j, l, ints;

printf("\n\nNumero de primeros caracteres a eliminar: "); scanf("%d",&ints);
system("cls");
for (i=0; i<*cantidad; i++){
l=strlen(aux[i].nombre); // utilizar el tamaño del nombre para cortar el siguiente for a la hora de renombrarlo.
for (j=0; aux[i].nombre[j]!='\0'; j++){
aux[i].nombre[j]=aux[i].nombre[j+ints]; // empieza substituyendo la posicion [0] de aux.nombre por lo que hay en la posición que ha marcado el user.
}
// puts (aux[i].nombre); // struct aux con todos los nombres ya modificados
}
}

void guardar (char ruta[], struct copia aux[], struct copia viejo[], int *cantidad){
char ruta_nuevo[MAXLONG], ruta_viejo[MAXLONG];
int i, opcion=0;
printf("\n\n");
   
   printf("Los archivos se renombraran de la siguiente manera:\n\n");
   for (i=0; i<*cantidad; i++){
    printf ("%s\n",aux[i].nombre);
}
printf("\n\nEstas segur@ de sobreescribir?\n");
printf("1) Yes\n");
printf("2) No\n");
printf("Opcion: "); scanf("%d",&opcion);

if (opcion==1){
for (i=0; i<*cantidad; i++){

strcpy (ruta_viejo,ruta);
strcat(ruta_viejo,viejo[i].nombre);
// printf("Archivo Viejo: %s\n",ruta_viejo);

strcpy (ruta_nuevo,ruta);
strcat (ruta_nuevo,aux[i].nombre);
// printf("Archivo Nuevo: %s\n\n",ruta_nuevo);

rename(ruta_viejo,ruta_nuevo);
   }
}
}

void mostrar(char ruta[]){
system ("cls");
carpeta = opendir(ruta);
printf("\nArchivos almacenados en: %s\n\n",ruta);
   while ((archivo = readdir(carpeta))){
if (strcmp(archivo->d_name,".")){
        if (strcmp(archivo->d_name,"..")){
        puts (archivo->d_name);
        }
       }
}
   closedir(carpeta);
}


@XSStringManolo

Prueba de varias formas, te lo pongo en pseudocidigo:
cadenaComillasDobles = '"'; //Metes las comillas dobles entre comillas simples. Si no te acepta las comillas pon = '/"';
rutaEntrecomiklada = cadenaComillasDobles + ruta + cadenaComillasDobles;

Si no te funciona en vez de comillas dobles usa comillas simples.

Si no funciona prueba cambiando el espacio por _

Y si sigue sin funcionar metele la barra de escape en la ruta antes de cada espacio. Tendras que poner doble barra de escape para que se te guarde 1 barra de escape antes del espacio de la ruta:

PrimeraParteDeLaRuta= "Desktop\\Nueva";
EscapeDeEspacio = "\\";
SegundaParteDeLaRuta = " Carpeta";

rutaFinal = PrimeraParteDeLaRuta + EscapeDeEspacio +SegundaParteDeLaRuta;
Al imprimir la rutaFinal saldria en pantalla: Desktop\Nueva\ Carpeta
Y se abriria Nueva Carpeta funciona así en algunos casos.
Prueba todas esas, alguna funcionara.

RayR

La función opendir acepta las rutas únicamente sin comillas, por lo tanto, lo de arrastrar el directorio no va a funcionar bien. Si arrastras una carpeta sin espacios en su nombre a la ventana de ejecución del programa, se pegará su nombre tal cual. Ejemplo:

Ruta de los archivos: c:\carpeta

Esto te va a funcionar correctamente. Pero si el directorio tiene espacios, Windows le agregará comillas:

Ruta de los archivos: "c:\mi carpeta"

Y ahí ya no va a funcionar. Así que es mejor que sólo le pidas al usuario que teclee las rutas, y sin comillas. De esa manera:

Ruta de los archivos: c:\mi carpeta

Te debe funcionar sí o sí. Si aún así te falla, estarás escribiendo algo mal.

Tauron

VALE! Tras mucho buscar ya he encontrado el problema. No se trata de los espacios, sino de los acentos.
Por alguna razón el programa se pasa la tabla ASCII por donde le place y cada vez que encuentra algún caracter con acento, lo interpreta como otro totalmente distinto. (por ejemplo la vocal "ú" la interpreta como si fuese "·")

Como solución he hecho printf de cada vocal con sus acentos para ver cómo lo interpreta la consola.
De esta manera identificar los acentos y modificar en el input la vocal por el carácter que entienda la consola, así en el output saldrá la vocal con el acento de manera correcta y la ruta acaba funcionando.

EN FIN, una movida por no tener en cuenta que estaba en windows. Estoy acostumbrado a utilizar linux y no tenia problemas con caracteres especiales.

RayR

#4
Sólo por curiosidad, y dejando de lado caracteres especiales, si arrastras un directorio con espacios a la ventana de tu programa, Windows le añade comillas, ¿cierto? Y de ser así, ¿lo acepta correctamente opendir? Porque hasta donde sé, Windows sí que las añade y así ya no funciona. A menos que haya cambiado el funcionamiento :o.

Editado: Se me olvidó lo principal que iba a poner. Eso de los acentos en Windows lo podrías solucionar llamando a este par de funciones (incluye <windows.h>):

SetConsoleCP (1252);
SetConsoleOutputCP(1252);


Con eso configuras la entrada y salida a la codificación latina.