elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Trabajando con las ramas de git (tercera parte)


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse, K-YreX)
| | |-+  Leer registro encabezado de archivo | C
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: Leer registro encabezado de archivo | C  (Leído 4,476 veces)
milx86

Desconectado Desconectado

Mensajes: 42


Ver Perfil
Leer registro encabezado de archivo | C
« en: 19 Octubre 2014, 06:54 am »

Buenas a todos.
Les cuento, tengo un archivo que almacena registros de longitud fija.

Mi archivo tiene un registro encabezado que almacena info sobre:
 * El número de registros de datos del archivo
 * La longitud de los registros de datos

+----------------------+
+ 5 + recordLength    +
+----------------------+
+ NR+ MAS CAMPOS  +
+----------------------+
+ 1 + ....   data  ........+
+ 2 + ....   data  ........+
+ 3 + ....   data  ........+
+ 4 + ....   data  ........+
+ 5 + ....   data  ........+

Código
  1. typedef struct Record{
  2.    char firstName[20];
  3.    char lastName[20];
  4.    char nationality[20];
  5.    char DNI[9];
  6.    int age;
  7.    int recordNumber;
  8. }Record;
  9.  
  10. typedef struct Header{
  11.    int numberOfRecords;
  12.    int recordLength;
  13. }Header;
Lo que hago al crear un archivo es inicializar los campos del registro encabezado y grabarlo:
Código
  1. void createFile(char* nameFile)
  2. {
  3.    FILE* fd;
  4.    Header buffer;
  5.    buffer.numberOfRecords = 0;
  6.    buffer.recordLength = sizeof(Record);
  7.    fd = fopen(nameFile,"wt");
  8.    fseek(fd,0,0);
  9.    fwrite(&buffer,1,sizeof(Header),fd);
  10.    // Compruebo el valor inicial que se grabo en numberOfRecords y me da 0, es correcto
  11.    printf("Valor: %d",buffer.numberOfRecords);
  12.    fclose(fd);
  13. }

Como se habrán dado cuenta cada registro Record tiene un campo el cual indica que  numero de registro es.
Código:
    int recordNumber;
Lo que hago para asignarle el valor al campo recordNumber, leo el encabezado(el numero de registros) y a ese le sumo uno, El cual seria el numero de registros actuales.
El problema es en la función para agregar un registro al archivo:
Código
  1. void addRecord(FILE** fd,Record data)
  2. {
  3.    struct Header buffer;
  4.    fread(&buffer, 1,sizeof(Header) , *fd);
  5.    buffer.numberOfRecords++;
  6.  
  7.    printf("Valor?: %d\n",buffer.numberOfRecords);
  8.  
  9.    data.recordNumber = buffer.numberOfRecords;
  10.    // Compruebo el contenido del registro recibido.
  11.    // Pero el campo NR no se actualizo... Sale un numero extrano
  12.    printf("% 10d% 12s% 12s% 12s% 12s% 12d\n",
  13.           data.recordNumber,
  14.           data.firstName,
  15.           data.lastName,
  16.           data.nationality,
  17.           data.DNI,
  18.           data.age
  19.          );
  20.    printf("\n\t\t\t    Press enter key to continue");
  21.    fgetchar();
  22. //
  23. //    int pos = (data.recordNumber-1) * buffer.recordLength + sizeof(Header);
  24. //    fseek(*fd,2,0);
  25. //    fwrite(&data,1, buffer.recordLength, *fd);
  26. //    fseek(*fd,0,0);
  27. //    fwrite(&buffer, 1,sizeof(Header), *fd);
  28. }

Mi problema es que cuando creo el archivo e inicializo el encabezado (numero de registros igual 0) funciona perfecto, pero cuando voy a leer luego el encabezado en ese campo esta un valor "extraño".

Aqui les dejo mi programa:
Código
  1. #ifdef __linux__
  2. #define CLEAN "CLEAR"
  3. #endif
  4.  
  5. #ifdef __MINGW32__
  6. #define CLEAN "CLS"
  7. #endif
  8.  
  9. #ifdef __MINGW64__
  10. #define CLEAN "CLS"
  11. #endif
  12.  
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <stdlib.h>
  16. #define TAM_CADENA 20
  17.  
  18. typedef struct Record
  19. {
  20.    char firstName[20];
  21.    char lastName[20];
  22.    char nationality[20];
  23.    char DNI[9];
  24.    int age;
  25.    int recordNumber;
  26. }Record;
  27.  
  28. typedef struct Header
  29. {
  30.    int numberOfRecords;
  31.    int recordLength;
  32. }Header;
  33.  
  34. void readLine(char cadena[], int tam);
  35. int readInt();
  36. void addRecord(FILE** fd,Record data);
  37. int getRecordNumber(FILE** fd);
  38. void createFile(char* nameFile);
  39. int subMenu(char* fileName);
  40. void menu();
  41.  
  42. int main(int argc, char *argv[])
  43. {
  44.    menu();
  45.    return 0;
  46. }
  47.  
  48. void menu()
  49. {
  50.    int op = 0;
  51.    char nameFile[TAM_CADENA];
  52.    do{
  53.        system(CLEAN);
  54.        printf("\n\t\t# | > _ _ _ _ _ _ __ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ < | #");
  55.        printf("\n\t\t# | >                                                < | #");
  56.        printf("\n\t\t# | >              [x1] Create File                  < | #");
  57.        printf("\n\t\t# | >              [x2] Open file for...             < | #");
  58.        printf("\n\t\t# | >              [x3] Dump File                    < | #");
  59.        printf("\n\t\t# | >              [x4] Search Record                < | #");
  60.        printf("\n\t\t# | >              [x5] Filter by Nationality        < | #");
  61.        printf("\n\t\t# | >              [x6] Exit                         < | #");
  62.        printf("\n\t\t# | >_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ < | #");
  63.        printf("\n\t\t##                                                      ##");
  64.        printf("\n\t\t\t        Enter option: ");
  65.        op = readInt();
  66.        switch(op){
  67.            case 1: printf("\n\t\t\t    Enter the file name: ");
  68.                    readLine(nameFile,TAM_CADENA);
  69.                    createFile(nameFile);
  70.                    printf("\n\t\t\t    Press enter key to continue");
  71.                    fgetchar();
  72.                    break;
  73.  
  74.            case 2: printf("\n\t\t\t    Enter the file name: ");
  75.                    readLine(nameFile,TAM_CADENA);
  76.                    subMenu(nameFile);
  77.                    break;
  78.  
  79.            case 3: printf("\n\t\t\t    Enter the file name: ");
  80.                    readLine(nameFile,TAM_CADENA);
  81.                    seeAll(nameFile);
  82.                    printf("\n\t\t\t    Press enter key to continue");
  83.                    fgetchar();
  84.                    break;
  85.  
  86.            case 4: printf("\n\t\t\t    Press enter key to continue");
  87.                    fgetchar();
  88.                    break;
  89.  
  90.            case 5: printf("\n\t\t\t    Press enter key to continue");
  91.                    fgetchar();
  92.                    break;
  93.  
  94.            case 6: printf("\n\t\t\t    Good bye :)");
  95.                    printf("\n\t\t\t    Press enter key to continue");
  96.                    fgetchar();
  97.                    break;
  98.  
  99.            default:printf("\n\t\t\t    [msgError]: Invalid option.");
  100.        }
  101.    }while(op!=6);
  102. }
  103.  
  104. int subMenu(char* fileName)
  105. {
  106.    FILE* fd;
  107.    if( (fd=fopen(fileName,"a+t")) == NULL )
  108.    {
  109.        printf("\nCould not open the file.");
  110.        return -1;
  111.    }
  112.    else
  113.    {
  114.        int op = 0, R;
  115.        Record buffer;
  116.        do{
  117.            system(CLEAN);
  118.            R = getRecordNumber(&fd);
  119.            printf("\n\t\t##                                                      ##");
  120.            printf("\n\t\t# | >>_ _ _++=[-> File: %s   R: %d<-]=++_ _ _ << | #", fileName,R);
  121.            printf("\n\t\t# | >_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ < | #");
  122.            printf("\n\t\t# | >                                                < | #");
  123.            printf("\n\t\t# | >              [x1] Add new records.             < | #");
  124.            printf("\n\t\t# | >              [x2] Change record                < | #");
  125.            printf("\n\t\t# | >              [x3] Close file                   < | #");
  126.            printf("\n\t\t# | >_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ < | #");
  127.            printf("\n\t\t##                                                      ##");
  128.            printf("\n\t\t\t        Enter option: ");
  129.            op = readInt();
  130.            switch(op){
  131.                case 1: printf("\n\t\t\t    Enter First Name: ");
  132.                        readLine(&buffer.firstName,TAM_CADENA);
  133.                        printf("\n\t\t\t    Enter Last Name: ");
  134.                        readLine(buffer.lastName,TAM_CADENA);
  135.                        printf("\n\t\t\t    Enter Nationality: ");
  136.                        readLine(buffer.nationality,TAM_CADENA);
  137.                        printf("\n\t\t\t    Enter DNI: ");
  138.                        readLine(buffer.DNI,9);
  139.                        printf("\n\t\t\t    Enter Age: ");
  140.                        buffer.age = readInt();
  141.                        addRecord(&fd, buffer);
  142.                        break;
  143.  
  144.                case 2: printf("\n\t\t\t    Press enter key to continue");
  145.                        fgetchar();
  146.                        break;
  147.  
  148.                case 3: fclose(fd);
  149.                        printf("\n\t\t\t    File closed.");
  150.                        break;
  151.  
  152.                default:printf("\n\t\t\t    [msgError]: Invalid option.");
  153.            }
  154.        }while(op!=3);
  155.    }
  156.    return 0;
  157. }
  158.  
  159. void createFile(char* nameFile)
  160. {
  161.    FILE* fd;
  162.    struct Header buffer;
  163.    buffer.numberOfRecords = 0;
  164.    buffer.recordLength = sizeof(Record);
  165.    fd = fopen(nameFile,"wt");
  166.    fseek(fd,0,0);
  167.    fwrite(&buffer,1,sizeof(Header),fd);
  168.    // Compruebo el valor inicial que se grabo en numberOfRecords
  169.    // 0 es correcto
  170.    printf("Valor de nr: %d",buffer.numberOfRecords);
  171.    fclose(fd);
  172. }
  173.  
  174.  
  175. int getRecordNumber(FILE** fd)
  176. {
  177.    struct Header buffer;
  178.    fread(&buffer, 1, sizeof(Header),*fd);
  179.    return buffer.numberOfRecords;
  180. }
  181.  
  182.  
  183. void addRecord(FILE** fd,Record data)
  184. {
  185.    struct Header buffer;
  186.    fread(&buffer, 1,sizeof(Header) , *fd);
  187.    buffer.numberOfRecords++;
  188.  
  189.    printf("Valor de nr: %d\n",buffer.numberOfRecords);
  190.  
  191.    data.recordNumber = buffer.numberOfRecords;
  192.    // Compruebo el contenido del registro recibido.
  193.    // Pero el campo NR no se actualizo... Sale un numero extraño
  194.    printf("% 10d% 12s% 12s% 12s% 12s% 12d\n",
  195.           data.recordNumber,
  196.           data.firstName,
  197.           data.lastName,
  198.           data.nationality,
  199.           data.DNI,
  200.           data.age
  201.          );
  202.    printf("\n\t\t\t    Press enter key to continue");
  203.    fgetchar();
  204. //
  205. //    int pos = (data.recordNumber-1) * buffer.recordLength + sizeof(Header);
  206. //    fseek(*fd,2,0);
  207. //    fwrite(&data,1, buffer.recordLength, *fd);
  208. //    fseek(*fd,0,0);
  209. //    fwrite(&buffer, 1,sizeof(Header), *fd);
  210. }
  211.  
  212. int seeAll(char* nameFile)
  213. {
  214.    FILE* fd;
  215.    if( (fd=fopen(nameFile,"rt")) == NULL )
  216.    {
  217.        printf("\nCould not open the file.");
  218.        return -1;
  219.    }
  220.  
  221.    else
  222.    {
  223.        struct Record buffer;
  224.        struct Header header;
  225.        fread(&header,1,sizeof(Header), fd);
  226.        while(fread(&buffer,1,header.recordLength,fd) == 1)
  227.        {
  228.            printf("% 10d% 12s% 12s% 12s% 12s% 12d\n",
  229.                   buffer.recordNumber,
  230.                   buffer.firstName,
  231.                   buffer.lastName,
  232.                   buffer.nationality,
  233.                   buffer.DNI,
  234.                   buffer.age
  235.                  );
  236.        }
  237.  
  238.        fclose(fd);
  239.    }
  240.    return 0;
  241. }
  242.  
  243. int readInt()
  244. {
  245.  char buf[BUFSIZ];
  246.  char *p;
  247.  long int i;
  248.  
  249.  if (fgets(buf, sizeof(buf), stdin) != NULL)
  250.  {
  251.    i = strtol(buf, &p, 10);
  252.    if (buf[0] != '\n' && (*p == '\n' || *p == '\0'))
  253.      return i;
  254.  }
  255. }
  256.  
  257. void readLine(char cadena[], int tam)
  258. {
  259.    char c;
  260.    fgets(cadena,tam,stdin);
  261.    if (cadena[strlen(cadena)-1] == '\n')
  262.        cadena[strlen(cadena)-1] = '\0';
  263.    else
  264.    {
  265.        cadena[tam-1] = '\0';
  266.        while((c = getchar()) != '\n'){};
  267.    }
  268. }

Gracias de antemano. :)


En línea

La abstracción es la clave para lidiar con la complejidad.
avesudra


Desconectado Desconectado

Mensajes: 724


Intentando ser mejor cada día :)


Ver Perfil
Re: Leer registro encabezado de archivo | C
« Respuesta #1 en: 21 Octubre 2014, 16:57 pm »

Ayer lo estuve mirando y es rarísimo, seguro que se escapa algo, pero no lo veo. Vale, justo cuando estaba escribiendo esto creo que me he dado cuenta del error, tú abres el archivo para escribirlo al desde el final no para leerlo(voy a mirar a ver si es eso)


En línea

Regístrate en
rir3760


Desconectado Desconectado

Mensajes: 1.639


Ver Perfil
Re: Leer registro encabezado de archivo | C
« Respuesta #2 en: 22 Octubre 2014, 00:46 am »

Mi problema es que cuando creo el archivo e inicializo el encabezado (numero de registros igual 0) funciona perfecto, pero cuando voy a leer luego el encabezado en ese campo esta un valor "extraño".
El problema principal se debe a que en la función "subMenu" abres el archivo en modo "a+t" y con ello todas las operaciones de escritura se realizaran al final del archivo sin importar el uso de funciones de posicionamiento como fseek y rewind. En su lugar debes abrir el archivo en el modo "r+b" cuidando que antes de cualquier operación de escritura te posiciones al principio o final del archivo (dependiendo si vas a escribir el encabezado o agregar un registro) mediante la función fseek.

Ademas se debe cambiar/corregir una parte significativa del programa:

* Si declaras una macro no debes darle un nombre que inicie con un guion bajo ya que esos nombres se reservan para la implementación (algunos ejemplos son __DATE__, __FILE__, __LINE__, etc.).

* Cuando se declara una función con paréntesis vacíos:
Código
  1. int readInt();
  2.  
  3. /* ... */
  4.  
  5. void menu();
Ello indica un numero no determinado de argumentos, para indicar que no recibe argumentos debes utilizar "(void)".

* Si no utilizas los argumentos pasados mediante la linea de comandos cambia la definición de la función principal a "int main(void) ..." o "int main() ...".

* La biblioteca estándar de C no incluye una función con el nombre "fgetchar", en su lugar utiliza getchar o mejor todavía elimina por completo esa llamada.

* En el bloque de prototipos falta la declaración de la función "seeAll".

* En la función "subMenu" en la llamada a "readLine":
Código
  1. readLine(&buffer.firstName, TAM_CADENA);
El operador "dirección de" (el '&') esta de mas en su primer argumento, eliminalo.

* En la función "readInt" no se especifica el valor a retornar si ocurre un error y si la linea es demasiado larga el restante se quedara en el bufer de la entrada estándar (para el caso mejor utiliza scanf para leer el entero y a continuación descarta el resto de la linea con un bucle.

* En la función "readLine" si el ultimo carácter no es el avance de linea no es necesario sobrescribir este con un '\0' porque fgets lo agrega automáticamente. Y el tipo de retorno de getchar es int, la función hay que cambiarla a:
Código
  1. void readLine (char cadena[], int tam)
  2. {
  3.   if (fgets(cadena, tam, stdin) != NULL){
  4.      size_t i = strlen(cadena) - 1;
  5.  
  6.      if (cadena[i] == '\n')
  7.         cadena[i] = '\0';
  8.      else {
  9.         int ch;
  10.  
  11.         while ((ch = getchar()) != EOF && ch != '\n')
  12.            ;
  13.      }
  14.   }
  15. }

* En la funcion "seeAll" el bucle para imprimir todos los registros:
Código
  1. while (fread (&buffer, 1, header.recordLength, fd) == 1){
  2.   /* ... */
  3. }
No funcionara correctamente, las razones de ello te las explique en tu tema Funcion que no puede retornar un struct [C].

Un saludo
En línea

C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language
milx86

Desconectado Desconectado

Mensajes: 42


Ver Perfil
Re: Leer registro encabezado de archivo | C
« Respuesta #3 en: 22 Octubre 2014, 17:09 pm »

Gracias a ambos por su ayuda.
En la universidad enseñan una mezcla de C/C++ que me incomoda, no creo que cuando termine acepten desarrollar proyectos de esa manera  :¬¬ , por lo que estoy aprendiendo C por mi cuenta con Programación en C | Joyanes, pero bueno sin salir del tema..

Tambien me di cuenta de otro error.
En mi función submenu estoy trabajando todo con el mismo fd y al inicio del submenu ya leo el encabezado(cuando muestro el nombre del archivo y el numero de registros.)
Y en la funcion para agregar vuelvo a leer el encabezado,pero el "cursor" esta posicionado despues del registro de encabezado , tengo que retroceder al inicio xD!

Estoy haciendo los cambios que me dijeron con el codigo que publique aqui y ya me funciona, cuando llegue a casa publicaré mi programa completo, espero tambien le sirva a alguien cuando visite el hilo  :).

Y por curiosidad(y sin ser chupamedias), quizá es por la experiencia que conoces tanto,como es que funciona el lenguaje y sus funciones, eso casi no e encontrado (o no e sabido buscar), en su mayoria dicen "que es lo que hace", pero no "como lo hace".
Me recomendarías alguna documentación de nivel básico, quiero conocer más a C.

Saludos
En línea

La abstracción es la clave para lidiar con la complejidad.
avesudra


Desconectado Desconectado

Mensajes: 724


Intentando ser mejor cada día :)


Ver Perfil
Re: Leer registro encabezado de archivo | C
« Respuesta #4 en: 22 Octubre 2014, 19:29 pm »

Gracias a ambos por su ayuda.
En la universidad enseñan una mezcla de C/C++ que me incomoda, no creo que cuando termine acepten desarrollar proyectos de esa manera  :¬¬ , por lo que estoy aprendiendo C por mi cuenta con Programación en C | Joyanes, pero bueno sin salir del tema..

Tambien me di cuenta de otro error.
En mi función submenu estoy trabajando todo con el mismo fd y al inicio del submenu ya leo el encabezado(cuando muestro el nombre del archivo y el numero de registros.)
Y en la funcion para agregar vuelvo a leer el encabezado,pero el "cursor" esta posicionado despues del registro de encabezado , tengo que retroceder al inicio xD!

Estoy haciendo los cambios que me dijeron con el codigo que publique aqui y ya me funciona, cuando llegue a casa publicaré mi programa completo, espero tambien le sirva a alguien cuando visite el hilo  :).

Y por curiosidad(y sin ser chupamedias), quizá es por la experiencia que conoces tanto,como es que funciona el lenguaje y sus funciones, eso casi no e encontrado (o no e sabido buscar), en su mayoria dicen "que es lo que hace", pero no "como lo hace".
Me recomendarías alguna documentación de nivel básico, quiero conocer más a C.

Saludos
En cuanto a lo último el "cómo lo hace" no es parte del desarrollador de otras aplicaciones pues no hay que reinventar la rueda, pero entiendo tu curiosidad pues yo también la tuve y la sigo teniendo, no tienes más que descargar la glibc y leer el código ;)

http://www.gnu.org/software/libc/

http://ftp.gnu.org/gnu/glibc/ De aquí puedes descargarte el código de todas las funciones que usas de C, como están hechas y tal, no creo que te enteres de mucho al igual que yo no lo hice en su momento, es una biblioteca demasiado grande, pero si puedes echarle un ojo a las funciones matemáticas que eso es curioso.
Saludos
« Última modificación: 22 Octubre 2014, 19:34 pm por avesudra » En línea

Regístrate en
Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
Problemas al leer el registro de Windows
Programación Visual Basic
aaronduran2 8 3,287 Último mensaje 20 Septiembre 2008, 19:17 pm
por aaronduran2
Leer el valor de una key del registro de windows
Programación C/C++
extreme69 6 7,052 Último mensaje 20 Febrero 2011, 06:02 am
por extreme69
Leer el registro de windows?
Programación C/C++
KroSaver 2 4,075 Último mensaje 11 Agosto 2011, 03:16 am
por kiriost
Error al querer leer el último registro en archivo .txt [python] « 1 2 »
Scripting
DanielPy 16 8,857 Último mensaje 31 Marzo 2018, 08:38 am
por Avispon99
no se como hacer que funcione archivo de encabezado en C++
Programación C/C++
ONOXIMORON 1 2,481 Último mensaje 29 Mayo 2020, 18:55 pm
por K-YreX
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines