PDA

View Full Version : [C]Chiarimenti fopen


Metalmino
01-09-2012, 11:52
Salve forum, vorrei alcuni chiarimenti riguardo il comando fopen (per aprire e scrivere informazioni su file).

Per far ciò vi posto un esame universitario, dove in pratica la traccia come primo step chiedeva di aprire in lettura un file di testo .txt dove vi erano scritte le seguenti informazioni:

88-07-73507-X;2011;Novecento;Alessandro Baricco;10.60
88-07-92163-X;2011;Omero, Iliade;Alessandro Baricco;8.08
ecc...

dove la prima parte indica il codice ISBN (con la variabile x da calcolare), indi anno, autore, prezzo ecc... e ogni informazione è separata da un punto e virgola.

Perfetto, ordunque io so che per leggere i file da testo si fa così:

FILE *file_lettura;
file_lettura = fopen("books.txt", "r");
if(fp == NULL)
printf(“ERRORE in apertura del file”);
while(!feof(file_lettura))
{
fscanf(file_lettura, "%d", &numero);
printf("numero letto: %d\n", numero);
}

nel caso di numeri o cambiando la variabile dove mettere le informazioni in caso di char ecc...

Ma in questo caso come si fà? Come si fa a far riconoscere il punto e virgola come fine informazione in lettura? Come posso mettere, per esempio, l'isbn in un intero, il nome in uno char* ecc...? Illuminatemi please!

Il prof nella soluzione ha messo il seguente codice:

FILE *fp = fopen("books.txt", "r");
if (fp == NULL)
{
printf("ERROR - File books.dat not found\n");
return 0;
}

while(!feof(fp))
{

strcat(item.key,"\0");
fscanf(fp,"\n%256[^;]",item.key);
compute_checksum(item.key);

fscanf(fp,"\n;%d",&(item.pubyear));

strcat(item.title,"\0");
fscanf(fp,"\n;%256[^;]",item.title);

strcat(item.author,"\0");
fscanf(fp,"\n;%256[^;]",item.author);

fscanf(fp,"\n;%f",&(item.price));

Dove so che, ovviamente, per memorizzare l'ISBN accede all' item.key ma come fa a far riconoscere il punto e virgola come fine informazione? Non riesco a capire.

demos88
01-09-2012, 13:43
mmmh effettivamente non mi è molto chiaro quello che fa la soluzione, io avrei utilizzato un strtok: http://www.elook.org/programming/c/strtok.html

otelmao
02-09-2012, 11:12
il c è un bel po' di tempo che non lo uso come linguaggio ma a vedere il contenuto del file le righe vengono ripetute in modo regolare a livello contenutistico, quindi perchè non creare una struct che abbia come dati ogni singolo elemento della riga? usando una struct non avresti il problema di capire quando finisce dato che andresti a leggere una quantità di dati pari alla lunghezza della struct stessa quindi avresti la stringa dell'isbn e così via...

qui hai una spiegazione del concetto di struct
http://www.html.it/pag/15410/struct-typedef-e-union/

sottovento
03-09-2012, 06:58
FILE *fp = fopen("books.txt", "r");
if (fp == NULL)
{
printf("ERROR - File books.dat not found\n");
return 0;
}

while(!feof(fp))
{

strcat(item.key,"\0");
fscanf(fp,"\n%256[^;]",item.key);
compute_checksum(item.key);

fscanf(fp,"\n;%d",&(item.pubyear));

strcat(item.title,"\0");
fscanf(fp,"\n;%256[^;]",item.title);

strcat(item.author,"\0");
fscanf(fp,"\n;%256[^;]",item.author);

fscanf(fp,"\n;%f",&(item.price));


Nel tuo codice, nel caso si abbia problemi in apertura del file, semplicemente scriverai un messaggio e continuerai l'esecuzione, causando un errore runtime. Correttamente, nel codice del professore questo non avviene.

Passiamo al pezzo forte: la fscanf().
fscanf(fp,"\n%256[^;]",item.key);
dice di lettere un massimo di 256 caratteri, fino ad un eventuale punto e virgola; infatti [^;] significa "NON LEGGERE il punto e virgola";

fscanf(fp,"\n;%d",&(item.pubyear));
legge un numero preceduto dal punto e virgola, quello non letto prima.

Il codice e' ok. Personalmente preferisco leggere l'intera linea mediante la fgets() e poi analizzarla, magari mediante strtok() come suggerito da demos88 oppure strchr(), strstr(), ....
E' anche piu' di una questione di stile: un eventuale errore compiuto dall'utente nella compilazione del file di ingresso potrebbe causare il crash (meglio: un ciclo infinito) nel codice del professore, mentre potrebbe essere benissimo catturato e gestito mediante fgets().
La fscanf() infatti ha il brutto vizio di fallire lasciando inalterato il puntatore al carattere corrente da leggere, in modo da essere riletto alla volta successiva e quindi continuare a fallire :D
Non e' proprio il caso di questo codice, ma in caso di errore il codice del tuo professore non sara' in grado di accorgersene facilmente.... d'altronde il professore sta facendo didattica, non sta programmando un'applicazione vera....