Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
C/C++ - Gestione files, fwrite ed fread
Forum - C/C++ - Gestione files, fwrite ed fread

Avatar
nylus (Normal User)
Newbie


Messaggi: 8
Iscritto: 08/11/2010

Segnala al moderatore
Postato alle 21:29
Lunedì, 08/11/2010
Considerate il seguente frammento di codice :
Codice sorgente - presumibilmente C++

  1. struct Database {
  2.         int numero;
  3. } var_database;
  4.  
  5. void crea_file (void);
  6. void leggi_file (void);
  7.  
  8. int main(){
  9.  
  10.         crea_file ();
  11.         leggi_file ();
  12.                
  13.         system("pause");
  14.         return 0;      
  15. }
  16.  
  17. void crea_file (void) {
  18.  
  19.         FILE * file;
  20.         var_database.numero = 10;
  21.  
  22.         file = fopen ("prova.dat", "w");
  23.         fwrite (&var_database, sizeof (struct Database), 1, file);
  24.         fclose (file);
  25. }
  26.  
  27.  
  28. void leggi_file (void) {
  29.  
  30.         FILE * file;
  31.        
  32.         file = fopen ("prova.dat", "r");
  33.                
  34.         while (!feof (file)) {
  35.                 fread (&var_database, sizeof (struct Database), 1, file);
  36.                 printf ("%d\n", var_database.numero);
  37.         }
  38.  
  39.         fclose (file);
  40. }



La funzione scrivi_file ()  crea il file "database.dat" e vi immagazzina al suo interno, attraverso fwrite, la struttura Database con il membro "numero" inizializzato a 10.
La funzione leggi_file () apre "database.dat" in modalita' lettura, immagazzina il contenuto nella variabile struttura "var_database" e lo visualizza grazie a printf.
Il problema e' che il programma manda in output due volte il numero 10, come se fwrite avesse imagazzinato nel file due volte l' oggetto "var_database" (quando invece avrebbe dovuto imagazzinarne solo uno).

Questa e' la versione semplificata di quello che mi accade ad un progetto molto piu' corposo a cui sto lavorando, non riesco a capirne il motivo.

Ringrazio anticipatamente qualsiasi eventuale risposta !

PM Quote
Avatar
Pitagora (Member)
Expert


Messaggi: 367
Iscritto: 12/06/2010

Segnala al moderatore
Postato alle 22:25
Lunedì, 08/11/2010
Codice sorgente - presumibilmente C/C++

  1. fwrite (&var_database.numero , 1 , sizeof(struct Database) , file );



Codice sorgente - presumibilmente C/C++

  1. fread (&var_database.numero , 1 , sizeof(struct Database) , file );



:k:

PM Quote
Avatar
TheKaneB (Member)
Guru^2


Messaggi: 1792
Iscritto: 26/06/2009

Segnala al moderatore
Postato alle 4:30
Martedì, 09/11/2010
Codice sorgente - presumibilmente C/C++

  1. while (!feof (file)) {
  2.                 fread (&var_database, sizeof (struct Database), 1, file);
  3.                 printf ("%d\n", var_database.numero);
  4.         }



Piazza un breakpoint dentro questo ciclo, e controlla il valore restituito da fread (che ti dice il numero esatto di bytes letti).

Considera che il valore di fread dovresti SEMPRE acquisirlo dentro una variabile, e confrontarlo con il valore da te aspettato.
Se restituisce qualcosa di meno vuol dire che è successo qualcosa di brutto.

Se itera 2 volte questo ciclo, significa che alla prima fread non viene raggiunta la fine del file. Questo potrebbe essere dovuto a settordicimila motivi diversi. Ad esempio perchè hai dimenticato di fare fseek(file, 0, SEEK_SET) prima del ciclo di lettura (la posizione dentro il file dovrebbe partire da zero, ma non si sa mai).

un'altra causa potrebbe essere dovuta al fatto che tratti i file come se fossero file ASCII. Usa "rb" e "wb". In questo modo eviterai problemi legati a speciali caratteri di stampa. Ad esempio tu scrivi il numero 10, che corrisponde all'andata a capo, quindi Windows aggiungerà automaticamente anche un secondo byte con il valore 13 che ti va a sballare il contenuto del file.

Questo è dovuto al fatto che Windows converte al volo le letture/scritture di file ASCII, sostituendo il carattere 10 (andata a capo stile Unix) con la coppia 10-13 (andata a capo stile Windows).

Non mi vengono altre idee per il momento, intanto prova queste cose (ma una alla volta, finchè non trovi quella giusta) e vediamo se risolvi...


@Pitagora: ma che stai a dì?

PM Quote
Avatar
nylus (Normal User)
Newbie


Messaggi: 8
Iscritto: 08/11/2010

Segnala al moderatore
Postato alle 10:50
Martedì, 09/11/2010
Allora andiamo con ordine :

Il suggerimento di Pitagora non funziona, da esattamento lo stesso output che ho descritto nel primo post.

Per quanto riguarda quello che dice TheKaneB, ho provato a :
- usare il metodo lettura e scrittura binaria, ma non e' cambiato nulla.
- aggiungere un fseek (file, 0, SEEK_SET) prima del ciclo while in modo che fossi sicuro che la ricerca partisse dall' inizio, ma anche qui non e' cambiato nulla.
- usare entrambi, ed ancora niente :d
- poi infine ho provato con il breakpoint  
Codice sorgente - presumibilmente C/C++

  1. while (!feof (file)) {
  2.                 size = fread (&var_database, sizeof (struct Database), 1, file);
  3.                 printf ("%d\n", var_database.numero);
  4.                 printf ("%d\n", size);
  5.                 /* BREAKPOINT */
  6.         }



il breakpoint e' dopo il secondo printf. Il ciclo itera due volte : la prima il valore "size" (restituito da fread) e' uguale ad 1, mentre la seconda volta e' uguale a 0.

Quindi, come dicevi tu, e' proprio un valore minore a quello che mi aspettavo, avrebbe dovuto restituire un valore pari a 4 (bytes) e non 1.
Il problema e' ora capire quel "qualcosa di brutto" che e' successo :rofl:

PM Quote
Avatar
TheKaneB (Member)
Guru^2


Messaggi: 1792
Iscritto: 26/06/2009

Segnala al moderatore
Postato alle 14:10
Martedì, 09/11/2010
se fread restituisce 0, vuol dire che è finito il file. Evidentemente l'implementazione di feof() non è attendibile, perchè il file risulta "terminato" soltanto dopo averlo forzato a leggere oltre l'ultimo byte.

A questo punto io riscriverei il ciclo in modo tale da effettuare prima la fread, e poi il controllo sul size per vedere se è finito il file, e scarterei l'uso di feof() che evidentemente non va bene per questo esercizio.

PM Quote
Avatar
nylus (Normal User)
Newbie


Messaggi: 8
Iscritto: 08/11/2010

Segnala al moderatore
Postato alle 18:33
Martedì, 09/11/2010
Ho risolto scrivendo questo ciclo :

Codice sorgente - presumibilmente C++

  1. fseek (file, 0, SEEK_SET);
  2.         size = fread (&var_database, sizeof (struct Database), 1, file);
  3.  
  4.         for (x=1; size!=0; x++){
  5.                 printf ("%d\n", var_database.numero);
  6.                 fseek (file, x * sizeof (struct Database), SEEK_SET);
  7.             size = fread (&var_database, sizeof (struct Database), 1, file);
  8.         }



fread() l'ho messa a fine ciclo in modo tale che questo fallisca (quando size = 0) prima che venga raggiunta la successiva printf() e che venga quindi visualizzato il valore "di troppo".
Grazie per la pazienza ed il tempo che mi hai dedicato :k:

PM Quote