Foros del Web » Programación para mayores de 30 ;) » C/C++ »

Posicionarse en el registro inicial después de una búsqueda [C]

Estas en el tema de Posicionarse en el registro inicial después de una búsqueda [C] en el foro de C/C++ en Foros del Web. Hola gente. Una consultita más sobre archivo, estoy en la parte de modificación de un registro y lo que hace el programa es verificar si ...
  #1 (permalink)  
Antiguo 03/04/2015, 12:20
rdv316
Invitado
 
Mensajes: n/a
Puntos:
Posicionarse en el registro inicial después de una búsqueda [C]

Hola gente.
Una consultita más sobre archivo, estoy en la parte de modificación de un registro y lo que hace el programa es verificar si la nueva palabra ingresada en inglés no exista, para eso tengo que recorrerlo hasta que encuentre la palabra o hasta el final, cuando termina la verificación tengo que regresar nuevamente al registro original para por ej. Si se desea grabar la modificación no escriba en cualquier lugar sino en el registro correcto.-
Concretamente la pregunta es: ¿Cómo guardo el registro antes de la búsqueda? , intentaría con el siguiente código pero no estoy seguro si es lo correcto.-

Código:
    ..........................
     long tam;
	
     tam=sizeof(trad);
     fseek(ptrFile, 0, SEEK_END);
     registros=ftell(ptrFile)/tam;	
     ...........................
El código no lo pongo porque tiene 251 líneas y me parece que no es necesario.-
Saludos.
Daniel
  #2 (permalink)  
Antiguo 03/04/2015, 18:34
Avatar de vangodp  
Fecha de Ingreso: octubre-2013
Mensajes: 934
Antigüedad: 10 años, 6 meses
Puntos: 38
Respuesta: Posicionarse en el registro inicial después de una búsqueda [C]

A ver si te sirve... Si lo ves complicado te explico lo que tengas duda XD

Código C:
Ver original
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <windows.h>
  4.  
  5. typedef struct {
  6.     char marcado;
  7.     char ingles[30];
  8.     char espaniol[30];
  9. } Traductor;
  10.  
  11. int main () {
  12.     FILE* ptrFile;
  13.     ptrFile = fopen ( "archivo.txt", "w+" );
  14.     char buscado[30];
  15.  
  16.     if ( ptrFile == NULL ) {
  17.         printf ( "No ha sido posible abrir archivo.txt" );
  18.         return 1;
  19.     }
  20.  
  21.     Traductor temp;
  22.     Traductor t[5] = {
  23.         { 0, "door", "puerta"},
  24.         { 0, "window", "ventana"},
  25.         { 0, "rueda", "wheel"},
  26.         { 0, "main", "principal"},
  27.         { 0, "out", "salida"}
  28.     };
  29.     //Nos genera un archivo con el contenido de t ya que abrimos con el atributo w+, asi nos centramos
  30.     //solo en su funcionamiento =). Tambien podemos escribir en el...El puntero siempre estará al final tras escribir en el.
  31.     fwrite ( t, sizeof ( Traductor ) * 5, 1, ptrFile );
  32.    
  33.     printf ( " Entre con una palabra en ingles a buscar en el\nregistro(La palabra debe existir en la estructura t, o no XD ).\n" );
  34.     scanf ( "%29[^\n]%*c", buscado );
  35.  
  36.     long nRegistros;
  37.     fseek ( ptrFile, 0, SEEK_END ); // Colocar el cursor al final del fichero
  38.     nRegistros = ftell ( ptrFile ) / sizeof ( Traductor ); // Tamaño en registros
  39.     printf ( "Hay %d registros en el fichero.\n", nRegistros );    
  40.    
  41.     int contador = 0;
  42.     rewind ( ptrFile );    
  43.     while ( fread ( &temp, sizeof ( Traductor ), 1, ptrFile ) ) {
  44.         //Si la palabra existe en el fichero
  45.         if ( strcmp ( temp.ingles, buscado ) == 0 ) {
  46.             strcpy(temp.ingles, "CAMBIADO!INGLES"); //si encontramos la palabra ponemos eso en su lugar XD
  47.            
  48.             printf ( "\nLa palabra esta en el registro numero %d del fichero\n", contador+1 );
  49.            
  50.             fseek(ptrFile, sizeof ( Traductor )*contador, SEEK_SET);
  51.            
  52.             fwrite ( &temp, sizeof ( Traductor ), 1, ptrFile );            
  53.             break;
  54.         }
  55.        
  56.         contador ++;
  57.         //Si la palabra NO existe en el fichero
  58.         if ( contador == nRegistros ){
  59.             printf("\nLa palabra no se encuentra en ninguno de los %d registros del fichero\n", nRegistros);
  60.             break;
  61.         }
  62.     }
  63.  
  64.     fclose ( ptrFile );
  65.     getchar();
  66.     return  0;
  67. }

Suerte XD
  #3 (permalink)  
Antiguo 03/04/2015, 19:27
rdv316
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: Posicionarse en el registro inicial después de una búsqueda [C]

Hola vangodp.
Para que no pienses que olvide del asunto te contesto ahora porque creo que voy a tardar unos 15 días de 8 horas para asimilar todo tú código.-
Lo voy a estudiar detenidamente, cualquier duda (20) te consulto, si lo quieres editar en las líneas 39 y 59 tendrías que poner %ld en reemplazo de %d, mi compilador marca advertencias.-

Saludos.
Daniel
  #4 (permalink)  
Antiguo 04/04/2015, 01:38
Avatar de vangodp  
Fecha de Ingreso: octubre-2013
Mensajes: 934
Antigüedad: 10 años, 6 meses
Puntos: 38
Respuesta: Posicionarse en el registro inicial después de una búsqueda [C]

El programa crea un archivo(sobreescribiendo el anterior) con 5 registros para que posteriormente podemos buscar en el una palabra, esa es su función.

luego pido una palabra en ingles para buscar en el registro. Si abres el archivo verás que hay el contenido de t dentro del archivo.

obtengo el numero de bytes del registro con ftell ( ptrFile ) / sizeof ( Traductor ); y lo guardo en nRegistros. Viene explicado aquí: www.c.conclase.net/ficheros/?cap=004#inicio en la parte que pone "Calcular la longitud de un fichero".

La función ftell(fichero); me va decir cuantos Bytes hay en el fichero, cada registro tiene un tamaño de 61Bytes ya que has reservado 2 variables con 30 chars y una con un char que da en un total 61 Bytes por registro, todos tienen ese tamaño independientemente de si ocupas o no el tamaño completo ya que no se escribe en el pero si abres el archivo puedes apreciar que hay una separación entre las palabras muy grande.

Lo que hay en el archivo es lo que hay en t, 5 registros de 61 bytes cada o sea 5*sizeof(Traductor). ;)

Volviendo a ftell ( ptrFile )... Si ftell nos da el tamaño total en Bytes de 5 registros que sabemos que hemos puesto en el fichero el calculo seria ftell ( ptrFile ) / sizeof ( Traductor );, ese seria el numero de registros nRegistros. Podia poner directamente nRegistros = 5 ya que se que tiene un tamaño de 5. ¿Pero y en los casos que no se el tamaño? XD

Ahora que tenemos nRegistros entramos en el bucle de búsqueda. La magia esta en el contador puesto que a cada lectura con fread ( &temp, sizeof ( Traductor ), 1, ptrFile ) avanzamos un registro, si se encuentra lo que buscamos entramos en el primer if de ese bucle y lo frenamos para que no cuente más, yo le he cambiado la palabra en ingles por "CAMBIADO!INGLES" tu puedes tomar un valor por teclado para cambiar si quieres. XD

Ahora bien, ni siempre la palabra va existir en el fichero. ¿Si sabemos que nuestro fichero tiene 5 registros y no hemos encontrado a la palabra, es que la palabra no existe verdad? Para eso esta el segundo if, que averigua si el contador se puso a la par con nRegistros, lo que quiere decir que en el registro no le queda palabras por buscar y que a consecuencia no se encuentra tu palabra.

Si la palabra existe vas a verla cambiada por "CAMBIADO!INGLES" si no seguirá tal cual.

Ya no hay nada que explicar, el programa es muy sencillo, quitando los avisos que has dicho %ld todo ok XD

por si a la criatura esta no la conoces scanf ( "%29[^\n]%*c", buscado ); Te explico lo que hace. Lee 29 chars máximo hasta encontrar el enter, leyendo también espacios, tabuladores etc, evitando que entre enter en la cadena, y finalizando la con un '\0' al final. Si entras mas de 29 chars, el restante permanece en el buffer, entonces deberías limpiarlo.

Espero no haberte liado más jajaja

Suerte!
  #5 (permalink)  
Antiguo 04/04/2015, 02:13
 
Fecha de Ingreso: julio-2012
Mensajes: 133
Antigüedad: 11 años, 9 meses
Puntos: 22
Respuesta: Posicionarse en el registro inicial después de una búsqueda [C]

Hola rdv316.

Otro ejemplo con una función que te permite buscar una palabra en ambos idiomas:
Código C:
Ver original
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5.  
  6. #define SPA 'e'
  7. #define ENG 'i'
  8.  
  9. typedef struct {
  10.     char marcado;
  11.     char ingles[30];
  12.     char espaniol[30];
  13. } Traductor;
  14.  
  15. // Busca palabras en archivo
  16. long int searchWord( FILE* fp, char* word, char lang );
  17.  
  18. int main( ) {
  19.   FILE *fp;
  20.   Traductor tr;
  21.   char lang, str[30];
  22.   long int position;
  23.  
  24.   if( ( fp = fopen ( "traductor.dat", "rb+" ) ) == NULL ) {
  25.     perror( "Error" );
  26.     return EXIT_FAILURE;
  27.   }
  28.   // datos
  29.   strcpy( str, "window" );  // palabra buscada
  30.   lang = ENG; // idioma (tendrías que filtrar la entrada a: SPA o ENG)
  31.   position = searchWord ( fp, str, lang );  // buscar
  32.   // posicionarse en palabra buscada y mostrar
  33.   if ( position != -1 ) {
  34.     fseek ( fp, position - sizeof(tr)  , SEEK_SET );
  35.     fread ( &tr, sizeof(tr), 1, fp);
  36.     printf ( "%c %s %s\n\n", tr.marcado, tr.espaniol, tr.ingles );
  37.   } else
  38.     printf ( "Palabra no encontrada" );
  39.   fclose ( fp );
  40.   return EXIT_SUCCESS;
  41. }
  42.  
  43. /* Busca en el archivo una palabra en inglés o español ( preserva posición )
  44.    Parámetros: puntero al archivo, palabra a buscar, idioma
  45.    Devuelve: la posición en el archivo o -1 si no existe */
  46. long int searchWord( FILE* fp, char* word, char lang ) {
  47.   Traductor tr;
  48.   long int mark, pos;
  49.   lang = tolower(lang);
  50.  
  51.   // guardar posición actual
  52.   mark = ftell ( fp );
  53.   // posicionar al inicio
  54.   rewind ( fp );
  55.   // buscar
  56.   if (lang == 'e' ) {
  57.     while ( fread ( &tr, sizeof ( tr ), 1, fp ) && strcmp ( tr.espaniol, word ) );
  58.     pos = ( strcmp ( tr.espaniol, word ) == 0 ) ? ftell ( fp ) : -1;
  59.   } else {
  60.     while ( fread ( &tr, sizeof ( tr ), 1, fp ) && strcmp ( tr.ingles, word ) );
  61.     pos = ( strcmp ( tr.ingles, word ) == 0 ) ? ftell ( fp ) : -1;
  62.   }
  63.   // restaurar posición previa
  64.   fseek ( fp, mark, SEEK_SET );
  65.   // resultado
  66.   return pos;
  67. }

Saludos.

Última edición por ecfisa; 04/04/2015 a las 02:32
  #6 (permalink)  
Antiguo 04/04/2015, 12:12
rdv316
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: Posicionarse en el registro inicial después de una búsqueda [C]

Hola amigos.
Muchas gracias a los 2, ya conseguí lo que pretendía, luego voy a profundizar en los códigos de ambos para aprender cosas que seguramente desconozco.-
Una última ayudita, les pediría que recorran mi programita y me digan si está todo correcto o que debo corregir y que pasa si muevo el cursor más allá del último registro.-

Código:
#include <stdio.h>

typedef struct {
	char marcado;
	char ingles[30];
	char espaniol[30];
} Traductor;

int main(void){
	FILE *ptrFile;
	Traductor trad;
	long mark;
	
	if( ( ptrFile = fopen( "archivo.txt", "r" ) ) == NULL ){
		perror( "Error" );
		return 1;
	}

	// el modo r posiciona el cursor al comienzo del archivo.
	fseek (ptrFile, 1*sizeof(trad), SEEK_CUR); // mover el cursor 1 registro asía abajo.
	mark = ftell ( ptrFile ); // guardar posición actual 
	fread (&trad, sizeof ( Traductor ), 1, ptrFile ); 
	printf( "\n\n %s === %s\n\n", trad.ingles, trad.espaniol );

	fseek (ptrFile, 3*sizeof(trad), SEEK_CUR); // mover el cursor 3 registro asía abajo.
	fread (&trad, sizeof ( Traductor ), 1, ptrFile );
	printf( "\n\n %s === %s\n\n", trad.ingles, trad.espaniol );

	fseek ( ptrFile, mark, SEEK_SET );	// restaurar posición previa.
	fread (&trad, sizeof ( Traductor ), 1, ptrFile );
	printf( "\n\n %s === %s\n\n", trad.ingles, trad.espaniol );

 fclose(ptrFile);
	return 0;

}
Saludos y muchas gracias.
Daniel

Última edición por rdv316; 04/04/2015 a las 13:02
  #7 (permalink)  
Antiguo 04/04/2015, 15:19
Avatar de vangodp  
Fecha de Ingreso: octubre-2013
Mensajes: 934
Antigüedad: 10 años, 6 meses
Puntos: 38
Respuesta: Posicionarse en el registro inicial después de una búsqueda [C]

Tienes un error.
Para ficheros de texto no deberías utilizar SEEK_CUR en fseek, debería ser SEEK_SET. O sea que deberíamos leer siempre desde el comienzo el segundo parámetro es el que se debería encargar de mover el cursor(puntero). Con fseek (ptrFile, 3*sizeof(trad), SEEK_CUR); estas diciendo al programa que se desplace 3 registros más adelante pero desde la posición actual. no se si se puede hacer eso.

Al menos es lo que pone en la referencia de cplusplus: http://www.cplusplus.com/reference/cstdio/fseek/

...En la parte que dice:
Cita:
For streams open in text mode, offset shall either be zero or a value returned by a previous call to ftell, and origin shall necessarily be SEEK_SET.
...Que traducido al google translator XD, nos dice:
Cita:
Para flujos abiertos en modo texto, el offset(offset es el segundo parámetro de fseek ;) ) deberá o bien ser cero o otro valor devuelto por una llamada previa a ftell y origin( 3º parámetro ) deberá necesariamente ser SEEK_SET.
Ahora bien.. No se si esto es cierto o no debido que soy muy noobs XDD. A ver si alguien con más exp nos aclara eso.

Tampoco sabría decirte que pasa si leyemos más allá del fin, pero parece que no se produce la lectura.

Entonces la parte de mi código que te puse seria invalida ya que uso SEEK_END...¡PERO FUNCIONA!
Código C:
Ver original
  1. long nRegistros;
  2.     fseek ( ptrFile, 0, SEEK_END ); // Colocar el cursor al final del fichero
  3.     nRegistros = ftell ( ptrFile ) / sizeof ( Traductor ); // Tamaño en registros
  4.     printf ( "Hay %d registros en el fichero.\n", nRegistros );

No se la verdad... Espero que nos aclaren por que ya tengo dudas hasta yo jajaj.

Suerte!
  #8 (permalink)  
Antiguo 04/04/2015, 15:48
lareto
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: Posicionarse en el registro inicial después de una búsqueda [C]

Llego tarde, pero quería alertar que no es correcto usar el sizeof de una struct para lectura o escritura en archivos, porque el tamaño (el size) de una struct depende del "data alignment" del compilador (o de cómo se haya seteado por línea de comando), y de la posición relativa de los miembros dentro de la struct. Pongo un ejemplo:
Código C++:
Ver original
  1. #include <iostream>
  2.  
  3. struct ejemplo1 {
  4.     char a;
  5.     int b;
  6.     double c;
  7. };
  8.  
  9. struct ejemplo2 {
  10.     double c;
  11.     char a;
  12.     int b;
  13. };
  14.  
  15. struct ejemplo3 {
  16.     int b;
  17.     double c;
  18.     char a;
  19. };
  20.  
  21. int main()
  22. {
  23.     std::cout << "sizof(char) + sizof(int) + sizeof(double) = "
  24.               << sizeof(char) + sizeof(int) + sizeof(double) << '\n';
  25.     std::cout << "sizeof(ejemplo1) = " << sizeof(ejemplo1) << '\n';
  26.     std::cout << "sizeof(ejemplo2) = " << sizeof(ejemplo2) << '\n';
  27.     std::cout << "sizeof(ejemplo3) = " << sizeof(ejemplo3) << '\n';
  28. }
  #9 (permalink)  
Antiguo 04/04/2015, 16:39
Avatar de vangodp  
Fecha de Ingreso: octubre-2013
Mensajes: 934
Antigüedad: 10 años, 6 meses
Puntos: 38
Respuesta: Posicionarse en el registro inicial después de una búsqueda [C]

ya... Llevas razón, pero en ese caso no afecta ya que todos los campos son chars.
En todo caso será mejor leer aquí para entender mejor y evitar futuros errores: http://c.conclase.net/curso/?cap=011b#STR_sizeof

A eso también se le dice alineación de bytes o byte-aling.

Lo mejor seria serializar todo en cadena de caracteres y enviar al archivo, luego pasar por el proceso inverso a la hora de leer.
  #10 (permalink)  
Antiguo 04/04/2015, 17:06
rdv316
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: Posicionarse en el registro inicial después de una búsqueda [C]

Hola.
Loreto, muchas gracias por tu participación, me podrías decir como seria la manera correcta sin sizeof.-

Cita:
Iniciado por vangodp Ver Mensaje
....Lo mejor seria serializar todo en cadena de caracteres y enviar al archivo, luego pasar por el proceso inverso a la hora de leer.
Vangodp, hace más de 2 meses que me propusieron hacer eso de serializar y nadie me supo poner un ej. ni tampoco pude encontrar en internet nada al respecto ¿me podrías dar algún ej. alguna guia ?

Saludos.
Daniel
  #11 (permalink)  
Antiguo 04/04/2015, 17:54
lareto
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: Posicionarse en el registro inicial después de una búsqueda [C]

Para escribir y leer estructuras a y desde un archivo, yo haría dos funciones que escribieran y leyeran cada uno de los miembros. Por ejemplo:
Código C++:
Ver original
  1. void escribe_traductor(FILE *fp, Traductor *traductor)
  2. {
  3.     fwrite(&traductor->marcado, sizeof(char), 1, fp);
  4.     fwrite(traductor->ingles, sizeof(char), 30, fp);
  5.     fwrite(traductor->espaniol, sizeof(char), 30, fp);
  6. }
  7.  
  8. void lee_traductor(FILE *fp, Traductor *traductor)
  9. {
  10.     fread(&traductor->marcado, sizeof(char), 1, fp);
  11.     fread(traductor->ingles, sizeof(char), 30, fp);
  12.     fread(traductor->espaniol, sizeof(char), 30, fp);
  13. }
  #12 (permalink)  
Antiguo 04/04/2015, 18:45
Avatar de vangodp  
Fecha de Ingreso: octubre-2013
Mensajes: 934
Antigüedad: 10 años, 6 meses
Puntos: 38
Respuesta: Posicionarse en el registro inicial después de una búsqueda [C]

Como te dijo lareto gran maestro, esta muy bien. =)

Yo haría algo así:
Código C:
Ver original
  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. typedef struct {
  5.     char marcado;
  6.     char ingles[30];
  7.     char espaniol[30];
  8. } Traductor;
  9.  
  10. int main (){
  11.     FILE * f;
  12.    
  13.     f = fopen( "prueba.txt", "w+" );
  14.     if (  f == NULL ){
  15.         ferror(f);
  16.         return 1;
  17.     }
  18.    
  19.     //preparamos una estructura
  20.     Traductor t[5] = {
  21.         { '+', "door", "puerta"},
  22.         { '+', "window", "ventana"},
  23.         { '+', "rueda", "wheel"},
  24.         { '+', "main", "principal"},
  25.         { '+', "out", "salida"}
  26.     };
  27.    
  28.     //grabamos en el fichero la estructura
  29.     int i;
  30.     for ( i = 0; i < 5; i++ ){
  31.         fprintf( f, "%c %-30s %-30s\n",t[i].marcado, t[i].ingles,t[i].espaniol );
  32.        
  33.     }
  34.    
  35.     //volvemos a leer y sacamos lo leido por pantalla
  36.     Traductor temp;
  37.     rewind(f);
  38.     for ( i = 0; i < 5; i++ ){
  39.         fscanf( f, /*note el espacio antes de %c y lea el comentario->*/" %c %s %s",&temp.marcado, temp.ingles, temp.espaniol ); // el espacio inicial en la cadena de formato ignora leer el enter que grabamos anteriormente con fprintf para que cada estructura se guarde una abajo de otra y no todas seguidas XD
  40.         printf("%c %s %s\n",temp.marcado, temp.ingles, temp.espaniol);
  41.     }    
  42.    
  43.    
  44.     fclose(f);
  45.     getchar();
  46.     return 0;
  47. }

Así tienes hasta mas control en el formato de lo que va a salir en el fichero. Por ejemplo note que cada linea ahora es una estructura.
  #13 (permalink)  
Antiguo 06/04/2015, 06:11
rdv316
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: Posicionarse en el registro inicial después de una búsqueda [C]

Hola gente.
Tarde un tanto en responder porque estoy buscando lo que me faltaría para completar el tema y es cuando utilizar archivo de texto o archivo binario, la ventaja de uno sobre el otro, etc. Todavía no pude encontrar ninguna página que me aclare el tema, ni bien encuentre algo interesante lo posteo, para cerrar este post que realmente me aclaró muchos temas, muchas gracias a todos y espero encontrarlos siempre para disipar mis dudas que por cierto son muchas y Uds. Son muy claros para explicar.-
Si alguien desea hacer algún aporte Danielito muy agradecido.-

Saludos y un abrazo.
Daniel
  #14 (permalink)  
Antiguo 06/04/2015, 06:42
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 6 meses
Puntos: 204
Respuesta: Posicionarse en el registro inicial después de una búsqueda [C]

Cita:
Iniciado por rdv316 Ver Mensaje
Hola gente.
Tarde un tanto en responder porque estoy buscando lo que me faltaría para completar el tema y es cuando utilizar archivo de texto o archivo binario, la ventaja de uno sobre el otro, etc. Todavía no pude encontrar ninguna página que me aclare el tema, ni bien encuentre algo interesante lo posteo, para cerrar este post que realmente me aclaró muchos temas, muchas gracias a todos y espero encontrarlos siempre para disipar mis dudas que por cierto son muchas y Uds. Son muy claros para explicar.-
Si alguien desea hacer algún aporte Danielito muy agradecido.-

Saludos y un abrazo.
Daniel
Un archivo de texto únicamente debería contener caracteres imprimibles... es decir, letras, números, espacios y demás signos. Además, se caracteriza porque el archivo está dividido en líneas de texto (usando el mismo juego de símbolos para delimitar cada línea: \n, \r\n o \n\r). Un archivo de texto lo puedes editar perfectamente con el block de notas. Normalmente su contenido puede ser leído por el usuario sin problemas.

En un archivo binario no hay reglas... admite cualquier caracter. La edición de un fichero binario hay que hacerlo con editores binarios para no alterar la información almacenada en el mismo.

Etiquetas: inicial, int, programa, registro
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 00:46.