PDA

Visualizza la versione completa : [C] Scrittura dati di una rubrica su file per rileggerli comodamente


_Alfabetagamma_
11-01-2011, 21:43
Buona sera a tutti,
sono uno studente di ing. informatica al politecnico di Milano e stiamo praticamente terminando il corso sul C.

Ho creato una rubrica funzionante dove posso aggiungere voci, stamparle a video, riordinarle ed effettuare una ricerca con una stringa che viene di volta in volta inserita dall'utente (e che dà come risultato tutte le "voci" della rubrica che contengono la nostra stringa "di ricerca").

La mia domanda è se sia possibile scrivere tutta la rubrica su di un file e riuscire a leggerla comodamente. Mi spiego meglio. Ogni voce della rubrica è così composta:



typedef struct voce {
char nome[M];
char soprannome[M];
char cognome[M];
char numero[M];
} voce;


Se salvassi su di un file carattere per carattere (putc) o con una fpritf, otterei una serie di stringhe "scollegate". Vorrei sapere se esiste (su questo son certo) un metodo abbastanza veloce che permetta una lettura immediata alla riapertura del file/progetto/Pc.

Infatti per andare a leggere tutte le voci della rubrica dovrei sapere dove sono e salvarle volta per volta in una stringa nuova (cambiando lunghezza del nome/cognome...... cambierebbe anche la posizione nel file).

Grazie in anticipo per le vostre risposte, spero di essere stato abbastanza chiaro con la mia richiesta :D

linoma
11-01-2011, 21:46
Ti conviene usare il classico fgets/fputs semplicemente xche hai un fine stringa. Per il tuo problema puoi usare fwrite e fread.

ramy89
11-01-2011, 22:18
Ho incontrato lo stesso identico problema quando ho fatto la mia agenda elettronica,se tu vuoi scrivere i dati sul file in modo da poi poterli rileggere ordinatamente,una tecnica è di trattare il file riga per riga.
Ho costruito una funzione apposita,che può leggere da qualsiasi file,questa funzione alloca dinamicamente la memoria necessaria a ospitare l' intera stringa.La stringa viene letta finchè non incontra il carattere newline,ed aggiunge il terminatore automaticamente,diviene a tutti gli effetti una stringa allocata sull' heap da liberare successivamente:


char *input (FILE *fp)
{
char *buffer;
char checker;
int size=1;
buffer=(char*)malloc(sizeof(char));
if(buffer==NULL)
{
printf("Errore di allocazione della memoria");
exit(1);
}
while((buffer=getchar())!=10)
{
buffer[size-1]=checker;
size++;
buffer=(char*)realloc(buffer,size*sizeof(char));
if(buffer==NULL)
{
printf("Errore di allocazione della memoria");
exit(1);
}
}
buffer[size-1]='\0';
fflush(stdin);
}

Usando questa funzione leggo tutti i dati da file,scritti riga per riga.
Poi quando vado a scrivere una stringa con fprintf aggiungo la newline:


fprintf(fp,"%s\n",stringa);

E leggo tranquillamente come leggessi da stdin.
Poi nella struttura per identificarle puoi aggiungere un intero che le identifica,ad esempio ogni struttura ha un serial number,a seconda del numero di righe che ha una struttura capisci quante righe dovrai leggere.
Se tutte le strutture ad esempio hanno 7 righe,leggi 7 stringhe prima di passare a leggere la successiva.

deleted_29
11-01-2011, 23:49
c'è un approccio assai più semplice.
prima scrivi il numero di record, e poi i singoli campi.

in fase di lettura leggi la prima riga (il numero record), e fai un banale ciclo che legge direttamente riga per riga.

fine del problema.
----
Ci sono poi approcci più "portabili", ossai file a lunghezza fissa, o CSV.
Nel secondo caso inventati un delimitatore "strano" che ha poca probabilità
di esserci tra i dati, (tipo !\$), giustapponilo ai singoli campi, uniscili e crea tante righe quanti record hai.

Personalmente l'opzioni 1 è mooolto più semplice ed adatto per un progettino scolastico

_Alfabetagamma_
12-01-2011, 10:15
Perfetto l'idea riga per riga funziona, ora cercherò di applicarla ad un blocco di stringhe. Grazie mille per l'aiuto dato :)

ramy89
12-01-2011, 23:27
Prego :)
Comunque ho sbagliato,al posto della getchar va inserito fgetc(fp),altrimenti legge solo da stdin.

Ippo343
12-01-2011, 23:56
Io personalmente la scriverei in un file binario, usando fwrite e fread.
In questo modo scrivi una serie di record tutti uguali che possono essere facilmente e velocemente riletti in un'array di record (o un singolo record, se è per questo) senza nessuna complicazione aggiuntiva.
Tranne quella di non poter modificare il file con un editor di testo se ti dovesse servire.

ramy89
13-01-2011, 00:11
Un file .bin comunque lo puoi tranquillamente aprire col blocco note,non c'è differenza tra un file .txt e un file .bin,sono entrambe binari.

Ippo343
13-01-2011, 09:00
In linea teorica ok, ma nella pratica è diverso.

Se scrivi sul file usando una funzione che formatta l'output, ad esempio fprintf, scrive in effetti del testo. Ad esempio, per scrivere il numero "1234567", occupa 7 caratteri. Se poi scrivi "25" ne occupa 2, etc.
Se scrivi sul file usando fwrite, vengono scritti i dati in formato binario senza formattarli, perciò un intero, qualsiasi intero, occupa sempre 4 byte, ma è illeggibile in un editor di testo.

Usando fwrite trascrivi sul file il blocco di memoria occupato dalla variabile, bit per bit, e non è detto (anzi, se non sono stringhe è quasi certo) che i byte che formano la variabile siano caratteri leggibili, figurati modificabili (pensa che se scrivi un double sul file, se provi a modificarlo quasi di sicuro lo "rompi" dato che il formato del double è un po' intricato).

_Alfabetagamma_
13-01-2011, 16:56
Io ho praticamente risolto usando le fgets():



FILE* p;
char buff[200];
char* pil;

pil=fgets(buff, 200, p); /* Leggo una riga (200 serve tanto per tanto si ferma a \n) */

for(; !feof(p); num++)
{

buff[strlen(buff)-1] = '\0'; /* siccome lo \n lo tiene dentro la stringa, allora lo tolgo */
if( p==NULL ) break; /* se il file non contiene nulla si ferma */
strcpy(&voce[num].nome, buff);, 200, p); /* copio buff (senza a capo) nella stringa che mi serve */


fgets(buff, 200, p);
}





A questo punto nel ciclo for ci sono tante letture quanti voci della struct (nella mia altre 3). Così ogni ciclo prende n righe corrispondente a n campi, fino a quando non arriva alla fine del file. La lettura la faccio alla fine del for così il puntatore si sposta e riesce a riconoscere se il file è finito. Una buona sintesi delle risposte :) grazie ancora :)

Loading