Volcar cadena de fichero binario en C

Iniciado por mester, 26 Mayo 2015, 20:49 PM

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

mester

Hola, he estado buscando el problema que tengo pero no encuentro solucion alguna, resulta que quiero imprimir una cadena que he guardado en un fichero binario con la funcion fread tal que así:

        LIBROS libreria[200];
       FILE* fichero;
       FILE* lectura;
       char rlibreria[100];
       int read,opc;
       fichero = fopen("archivo.dat","rb+");
               libreria[0].numsoc=8;
               strcpy(libreria[0].isbn,"Hola");
               //fwrite(&libreria[0],1,100,fichero);
               fread(&read,1,100,fichero);
               printf("%d",read);
               fread(&rlibreria,1,100,fichero);
               printf("%s",rlibreria);
               fclose(fichero);

¿Me podríais decir donde esta el error? Porque los numeros enteros si que los imprime bien, pero los carácteres no. En este caso me imprime 'N='.
Justicia es dar a cada uno lo que se merece

Peregring-lk

El segundo parámetro de `fread` es el número de bytes que ocupa cada "objeto" que quieres leer, y el tercero, cuántos objetos quieres leer.

Así que tu `fread` de `read` está mal:

Código (cpp) [Seleccionar]

fread(&read, sizeof(int), 1, fichero);


Posiblemente, tu `fread` original (al tener 1, 100), ha intentando leer 100 chars, ha guardado el primero en `read`, y los demás, bueno..., lo que no sé cómo no te ha dado un `segmentation fault` de caballo xD. El caso es que después del primer `fread`, el fichero se ha quedado vacío y no ha quedado nada que guardar en `rlibreria`.

El `fread` de `rlibreria`, sin embargo, es correcto.


mester

Vale, y ahora, en el caso de que quiera recoger los datos de un struct ¿Como va?

fread(&libreria[x],sizeof(libreria[x]),1,fichero);
printf("%d %s %s",libreria[x].dato, libreria[x].cadena, libreria[x].borja);

Yo he hecho esto y recoge solo los dos primeros datos jeje, nada mas xd
Justicia es dar a cada uno lo que se merece

Peregring-lk

Yo `fread` nunca lo he utilizado, la verdad, pero asumo que de la siguiente forma:


// Asumo que las cadenas tienen almacenamiento para hasta 100 carácteres.
// Además, las cadenas de por sí son punteros, no hace falta pasarle su dirección
// de memoria. `fread` necesita un búfer (una dirección de memoria a partir de la
// cual meter cosas). Si ya tienes una cadena, la propia cadena en sí te sirve como búfer.
fread(&libreria[x].dato, sizeof(libreria[x].date), 1, fichero);
fread(libreria[x].cadena, sizeof(char), 100, fichero);
fread(libreria[x].borja, sizeof(char), 100, fichero);


Pero de todas formas, me da la impresión de que `fread` lee un fichero sin formato: es decir, pilla tantos bytes como le indiques por parámetro, pero no sabe si lo que está leyendo es un flotante, un entero o qué.

Date cuenta que la representación binaria de un número flotante, por ejemplo, no es igual a la representación binaria de una cadena (que representa un flotante). Me explico.
Si tienes en un fichero de una linea por ejemplo:


163.25


Su representación binaria será la representación binaria del carácter '1', seguida de la del carácter '6', y así sucesivamente hasta llegar al '5'. Sin embargo, la representación binaria de un número flotante en memoria será una cosa totalmente diferente (basado en mantisa/exponente).

Para ello, utiliza `fscanf`. Aparte de ser más cómodo, lee de un fichero con formato:


fscanf("%d%s%s", &libreria[x].dato, libreria[x].cadena, libreria[x].borja)


Así, `fscanf` saber que primero leerá un número decimal (y transformará los carácteres correspondientes del fichero en un número decimal), y luego leerá dos cadenas (`fscanf` sabe que las cadenas empiezan y terminan con espacios, saltos de líneas o tabuladores; no va a pillarte líneas enteras ni nada de eso). Ese `fscanf` leería bien un fichero como:


12 Hola amigos


El `12` iría para `.dato`, "Hola" para `.cadena`, y "amigos" para `.borja`.

mester

Vale, ya tengo el struct y tal, y esta bien, porque escribe los valores en el fichero binario y tal, pero el problema es que el struct tiene un vector de 200 porque el programa consiste en hacer una especie de registro de libreria. Pues el caso es que tengo dos funciones, una de lectura y otra de escritura, y a la hora de leer los datos del fichero solo lee la última estructura escrita. Por ejemplo:

typedef struct LIBROS{
int numsoc;
char fprest[11];
char isbn[13];
char titulo[255];
char autor[255];
}LIBROS;


void lectura(){
LIBROS libreria[200];
FILE *fichero;
int x;
fichero = fopen("archivo.dat","rb");
if(fichero==NULL)
printf("Error, el archivo no existe, rellena la libreria\n");
else{
printf("\nEscribe el libro del que deseas extraer los datos: ");
    scanf("%d",&x);
fread(&libreria[x],sizeof(libreria[x]),1,fichero);
  printf("\n\n\n\nNumero de socio: %d\nFecha de prestamo: %s\nISBN: %s\nTitulo: %s\nAutor: %s\n\n\n\n",libreria[x].numsoc, libreria[x].fprest, libreria[x].isbn, libreria[x].titulo, libreria[x].autor);
}
fclose(fichero);
}

¿Como puedo hacer que se estructuren los datos en el fichero?
He probado con la funcion fscanf() como me has dicho, pero no funciona, la unica forma es fread.
Justicia es dar a cada uno lo que se merece

Peregring-lk

¿Puedes poner un ejemplo de fichero de entrada?

mester

#6
Cita de: Peregring-lk en 27 Mayo 2015, 18:35 PM
¿Puedes poner un ejemplo de fichero de entrada?
Supongo que el problema está en que solo lee los primeros valores del fichero, y no se como hacer que lea valores intermedios ni nada, buscando el struct concreto.

#include<stdio.h>
#include<string.h>
typedef struct LIBROS{
int numsoc;
char fprest[11];
char isbn[13];
char titulo[255];
char autor[255];
}LIBROS;

void escritura(){
LIBROS libreria[200];
FILE *fichero;
int x;
fichero = fopen("archivo.dat","wb+");
printf("Escribe el numero del libro que deseas editar: ");
                scanf("%d",&x);
if(x>200)
printf("------Error, no hay memoria para mas de 200 libros");
if(x==0){
printf("------Error, no puedes rellenar el libro '0'\n");
system("sleep 3");
system("clear");
}
else{
printf("\n\n------------------------------------\n");
printf("Escribe el numero de socio: ");
scanf("%d",&libreria[x].numsoc);
fwrite(&libreria[x].numsoc,sizeof(int),1,fichero);
fflush(stdin);
printf("Escribe el ISBN del libro: ");
scanf("%s",libreria[x].isbn);
fwrite(&libreria[x].isbn,sizeof(char),13,fichero);
fflush(stdin);
printf("Escribe la fecha del prestamo en formato DD/MM/AAAA: ");
scanf("%s",libreria[x].fprest);
fwrite(&libreria[x].fprest,sizeof(char),11,fichero);
fflush(stdin);
printf("Escribe el titulo del libro: ");
scanf("%s",libreria[x].titulo);
fwrite(&libreria[x].titulo,sizeof(char),255,fichero);
fflush(stdin);
printf("Escribe el autor del libro: ");
scanf("%s",libreria[x].autor);
fwrite(&libreria[x].autor,sizeof(char),255,fichero);
printf("-------------------------------------\n\n\n");
fflush(stdin);
fclose(fichero);
}
}

void lectura(){
int numsoc;
char fprest[11];
char isbn[13];
char titulo[255];
char autor[255];
LIBROS libreria[200];
FILE *fichero;
int x;
fichero = fopen("archivo.dat","rb+");
if(fichero==NULL)
printf("------Error, el archivo no existe, rellena la libreria\n");
else{
printf("\nEscribe el libro del que deseas extraer los datos: ");
    scanf("%d",&x);
fread(&numsoc,sizeof(int),1,fichero);
fread(&isbn,sizeof(char),13,fichero);
fread(&fprest,sizeof(char),11,fichero);
fread(&titulo,sizeof(char),255,fichero);
fread(&autor,sizeof(char),255,fichero);
printf("\n\n\n\nNumero de socio: %d\nFecha de prestamo: %s\nISBN: %s\nTitulo: %s\nAutor: %s\n\n\n\n",numsoc, fprest, isbn, titulo, autor);
}
fclose(fichero);
}

void eliminar(){
if(remove("archivo.dat")!=0){
printf("------Error, el archivo no existe\n");
system("sleep 3");
}
else{
printf("El registro ha sido eliminado exitosamente\n\n");
system("sleep 3");
}
}

int main(){
int opc;
char resp;
system("clear");
do{
printf("1) Rellenar registros\n");
printf("2) Ver registros\n");
printf("3) Eliminar el registro\n");
printf("4) Salir\n");
scanf("%d",&opc);
switch(opc){
case 1: escritura(); system("clear"); break;
case 2: lectura(); break;
case 3: eliminar(); system("clear"); break;
case 4: printf("\tHasta luego\n"); system("sleep 3"); system("clear"); break;
default: printf("----Introduce un valor valido\n"); system("sleep 3"); system("clear"); break;}

}while(opc!=4);
return 0;
}
Justicia es dar a cada uno lo que se merece

Peregring-lk

¿Puedes poner un ejemplo de fichero de entrada?

Nota: Fichero de entrada (o entrada del programa) = fichero que tu programa debe leer.

mester

Cita de: Peregring-lk en 27 Mayo 2015, 21:11 PM
¿Puedes poner un ejemplo de fichero de entrada?

Nota: Fichero de entrada (o entrada del programa) = fichero que tu programa debe leer.
No se ponerte un ejemplo, porque el fichero que debe leer el programa lo genera el programa en la funcion escritura(); No se si el fallo esta en la lectura, en la escritura, o en ambos
Justicia es dar a cada uno lo que se merece

Peregring-lk

#9
Ok. ¿Y no puedes "ver" qué devuelve la función `escritura`? ¿Qué devuelve, un fichero temporal?

De todas formas, como esa función `escritura()` devolverá un `FILE*` (sea el fichero temporal o no), sencillamente, haz una copia de ese fichero en disco y ponle un nombre. Añade el siguiente código justo después de llamar a dicha función `escritura()`:


// Es decir, justo despues de que obtengas el fichero para que lo leas.
FILE* fichero = escritura();

FILE* copia = fopen("micopia.txt", "w+");

long pos = ftell(fichero); // Guardamos la posicion actual de `fichero`.

char buff[100]; // Buffer para leer de 100 en 100 caracteres.
unsigned leidos; // Si leidos == 0 (valor devuelto por `fread`) es que hemos llegado al final del fichero.

// Copiamos todo en el fichero "micopia.txt"
while ((leidos = fread(buff, sizeof(char), 100, fichero) != 0)
   fwrite(buff, sizeof(char), leidos, copia);

fseek(fichero, pos); // Dejamos el fichero original como estaba.
fclose(copia); // Cerramos nuestro fichero copia.

// Resto de tu programa.


Y con ésto, capturaras el fichero y crearás una copia ("micopia.txt") que puedes ver con un editor de texto cualquiera para saber qué devuelve.