Programmazione.it v6.4
Ciao, per farti riconoscere devi fare il login. Non ti sei ancora iscritto? Che aspetti, registrati adesso!
Info Pubblicità Collabora Autori Sottoscrizioni Preferiti Bozze Scheda personale Privacy Archivio Libri Corsi per principianti Forum
Forum :: Programmazione.it :: C :: Operazioni su un file
Scritto da Loris Stefano a.k.a. javoso89 il 03-07-2012 ore 10:41
Intel Cluster Studio XE
Devo svolgere delle operazioni su un file. In particolare devo poterci scrivere e leggerlo per effettuare confronti.
E' legato al progetto che sto facendo in cui ciò che scrivo sul file sono utenti (struct) caratterizzati da un nome utente, password ed un permesso (int). Prima di scrivere un utente sul file "login" devo verificare che non sia già presente un utente con quel nome. Il tutto l'ho svolto così ma.. non funziona:


//Registrazione Utente
  1. int registraUtente(Utente utente) {
  2.  
  3. 	//Cerco se utente è già presente, in tal caso ritorna 0
  4. 	Utente temp = cercaNome(utente);
  5.  
  6. 	if(strcmp(utente.nickname,temp.nickname) == 0) { //Nickname già scelto
  7. 		printf("Nome utente non disponibilen");
  8. 		return -1;
  9. 	}
  10.  
  11. 	int ds = open("login",O_WRONLY|O_APPEND);
  12. 	if(ds == -1) {
  13. 		return -1;
  14. 	}
  15.  
  16. 	int w = write(ds,&utente,sizeof(utente));
  17. 	if(w == -1) {
  18. 		return -1;
  19. 	}
  20.  
  21. 	close(ds);
  22. 	return 1;
  23. }

//Cerca se il nome dell'utente è già presente
  1. Utente cercaNome(Utente utente) {
  2.  
  3. 	Utente temp;
  4.  
  5. 	memset(temp.nickname,0,sizeof(temp.nickname));
  6. 	memset(temp.password,0,sizeof(temp.password));
  7.  
  8. 	int cont = 0;
  9.  
  10. 	//Apro il file login
  11.  
  12. 	FILE *f;
  13. 	f = fopen("login","r");
  14. 	if(f == NULL) {
  15. 		printf("Errore apertura elenco utentin");
  16. 		chiudiServer();
  17. 	}
  18.  
  19. 	//Conteggio gli utenti presenti
  20.  
  21. 	else {
  22.  
  23. 		while(fscanf(f,"%s %s %d",temp.nickname,temp.password,&temp.permesso) == -1) {
  24. 			if(errno != EINTR) {
  25. 				printf("nErrore fscanf 1n");
  26. 				chiudiServer();
  27. 			}
  28. 		}
  29. 		while(!feof(f)) {
  30. 			while(fscanf(f,"%s %s %d",temp.nickname,temp.password,&temp.permesso) == -1) {
  31. 				if(errno != EINTR) {
  32. 					printf("nErrore fscanf 2n");
  33. 					chiudiServer();
  34. 				}
  35. 			}
  36. 			++cont;
  37. 		}
  38.  
  39. 		printf("Numero utenti presenti: %dn", cont);
  40.  
  41. 		rewind(f); //Riposizionamento indice del file
  42.  
  43. 		//Ricerca dell'utente
  44. 		int i;
  45. 		for(i=0; i
Precedente: Client web service (WSDL, SOAP, PHP/JAVA)
Successiva: [MySQL error:MySQLDataset1]
Commenti:  Primi  «  Meno recenti  «  11 - 15 di 15
Intervento di Loris Stefano a.k.a. javoso89 del 12-07-2012 ore 14:48, Fossacesia (CH)
Plebeo
Plebeo
(38 interventi)
Iscritto il 21-04-2011
javoso89 ha scritto:
b_gin ha scritto:
Allora, ci sono due problemi:

1) la funzione write alla riga 18 di registraUtente scrive nickname, password e permesso tutti attaccati, senza spazi, per cui la fscanf non riconosce niente, dato che si aspetta qualcosa nella forma %s %s %d.
Io sostituirei la sequenza
open - write - close
con
fopen - fprintf(f, "%s %s %d\n", utente.nickname, utente.password, utente.permesso) - fclose


2) nella funzione cercaNome non capisco perché usi
  1. while(fscanf(f,"%s %s %d",temp.nickname,temp.password,&temp.permesso) == -1) {
  2. 	if(errno != EINTR) {
  3. 		printf("nErrore fscanf 1n");
  4. 		chiudiServer();
  5. 	}
  6. }
e simili, è ovvio che se usi un while il cont non aumenta mai.
Io riscriverei la funzione così:
  1. Utente cercaNome(Utente utente) {
  2.  
  3. 	Utente temp;
  4.  
  5. 	memset(temp.nickname,0,sizeof(temp.nickname));
  6. 	memset(temp.password,0,sizeof(temp.password));
  7.  
  8. 	int cont = 0;
  9.  
  10. 	//Apro il file login
  11.  
  12. 	FILE *f;
  13. 	f = fopen("login","r");
  14. 	if(f == NULL) {
  15. 		printf("Errore apertura elenco utenti\n");
  16. 		chiudiServer();
  17. 	}
  18.  
  19. 	//Conteggio gli utenti presenti
  20.  
  21. 	else {
  22. 		while(!feof(f)) {
  23. 			if (fscanf(f,"%s %s %d\n",temp.nickname,temp.password,&temp.permesso) == -1) {
  24. 				if(errno != EINTR) {
  25. 					printf("\nErrore fscanf 2\n");
  26. 					chiudiServer();
  27. 				}
  28. 			}
  29. 			++cont;
  30. 		}
  31.  
  32. 		printf("Numero utenti presenti: %d\n", cont);
  33.  
  34. 		rewind(f); //Riposizionamento indice del file
  35.  
  36. 		//Ricerca dell'utente
  37. 		int i;
  38. 		for(i=0; i < cont; i++) {
  39. 			if(fscanf(f,"%s %s %d\n",temp.nickname,temp.password,&temp.permesso) == -1) {
  40. 				if(errno != EINTR) {
  41. 					printf("\nErrore fscanf 2\n");
  42. 					chiudiServer();
  43. 				}
  44. 			}
  45. 			if(strcmp(utente.nickname,temp.nickname) == 0) { //Utente trovato
  46. 				if(fclose(f) != 0) {
  47. 					if(errno != EINTR) {
  48. 						printf("\nErrore fclose 1\n");
  49. 						chiudiServer();
  50. 					}
  51. 				}
  52. 				return temp;
  53. 			}
  54. 		}
  55.  
  56. 	        if(fclose(f) != 0){
  57.                         if(errno != EINTR){
  58.                                 printf("\nErrore fclose 2\n");
  59.                                 chiudiServer();
  60.                         }
  61.                 }
  62.  
  63.         Utente vuoto = { "NULL", "NULL", 0 }; //Utente non trovato
  64.         return vuoto;
  65. 	}
  66. }

A me così funziona.

PS: questo codice è poco ottimizzato ed è accettabile finché il numero di utenti è piccolo. Per fare le cose per bene (a parte la possibilità di usare un database) dovresti usare ad esempio un array di struct ordinate per nickname, in modo da eseguire la ricerca in tempo logaritmico. Inoltre è un grosso spreco di tempo contare gli utenti ogni volta: se proprio ti è indispensabile sapere il numero di utenti, dovresti memorizzarlo da qualche parte (ad esempio all'inizio del file o su un altro file) e incrementare il valore di 1 ogni volta che aggiungi un utente.

Grazie per l'aiuto, non appena ho tempo provo ad apportare le modifiche da te mostrate. Immaginavo che non fosse ottimizzato, purtroppo sono autodidatta di C, in facoltà non ci viene esattamente insegnato (solo le basi estreme, per differenze con il Java). Per ora lo realizzo così, poi magari in futuro mi permetterò di ottimizzarlo :)

Funziona perfettamente, grazie! Sarebbe interessante implementare la lista di struct in ordine lessicografico..
Intervento di B_gin a.k.a. b_gin del 13-07-2012 ore 09:32, Padova (PD)
Nobile
Nobile

(62 interventi)
Iscritto il 14-11-2010
La lista ordinata di struct è utile se:
1) il numero di utenti che prevedi di avere non è piccolo (a occhio direi almeno un centinaio)
2) il numero di ricerche di utenti che devi fare è molto più grande del numero di inserimenti di nuovi utenti (in generale questo è vero, ad esempio il numero di login che fanno tutti gli utenti in un giorno è molto più grande del numero di nuove iscrizioni)
3) la lista degli utenti è sempre in memoria, cioè il programma è sempre in esecuzione (e quindi non devi caricare la lista dal disco ogni volta che vuoi fare una ricerca); se non è così si può fare lo stesso ma dovresti usare un file per ogni utente e non so che impatto potrebbe avere questo sulla velocità del programma.

In questo caso puoi usare l'insertion sort per l'inserimento di nuovi utenti e la ricerca binaria per cercare un utente. Dato che in C non esiste l'equivalente del vector di C++ dovresti anche implementare una lista dinamica, cioè che aumenta di dimensione quando necessario, a meno che tu non abbia un'idea precisa di quanti utenti potrai mai avere al massimo.


Altrimenti ti puoi accontentare del tuo algoritmo e pulirlo un po', evitando di contare gli utenti ogni volta.
Intervento di Loris Stefano a.k.a. javoso89 del 13-07-2012 ore 11:10, Fossacesia (CH)
Plebeo
Plebeo
(38 interventi)
Iscritto il 21-04-2011
b_gin ha scritto:
La lista ordinata di struct è utile se:
1) il numero di utenti che prevedi di avere non è piccolo (a occhio direi almeno un centinaio)
2) il numero di ricerche di utenti che devi fare è molto più grande del numero di inserimenti di nuovi utenti (in generale questo è vero, ad esempio il numero di login che fanno tutti gli utenti in un giorno è molto più grande del numero di nuove iscrizioni)
3) la lista degli utenti è sempre in memoria, cioè il programma è sempre in esecuzione (e quindi non devi caricare la lista dal disco ogni volta che vuoi fare una ricerca); se non è così si può fare lo stesso ma dovresti usare un file per ogni utente e non so che impatto potrebbe avere questo sulla velocità del programma.

In questo caso puoi usare l'insertion sort per l'inserimento di nuovi utenti e la ricerca binaria per cercare un utente. Dato che in C non esiste l'equivalente del vector di C++ dovresti anche implementare una lista dinamica, cioè che aumenta di dimensione quando necessario, a meno che tu non abbia un'idea precisa di quanti utenti potrai mai avere al massimo.


Altrimenti ti puoi accontentare del tuo algoritmo e pulirlo un po', evitando di contare gli utenti ogni volta.

Il mio programma è soltanto una simulazione la cui traccia è molto generica, possiamo realizzarlo come vogliamo. Ovviamente se implementassi quello che dici il 30 sarebbe assicurato :-p Ho eliminato il conteggio degli utenti, effettivamente inutile.
Intervento di Loris Stefano a.k.a. javoso89 del 19-07-2012 ore 15:12, Fossacesia (CH)
Plebeo
Plebeo
(38 interventi)
Iscritto il 21-04-2011
javoso89 ha scritto:
b_gin ha scritto:
La lista ordinata di struct è utile se:
1) il numero di utenti che prevedi di avere non è piccolo (a occhio direi almeno un centinaio)
2) il numero di ricerche di utenti che devi fare è molto più grande del numero di inserimenti di nuovi utenti (in generale questo è vero, ad esempio il numero di login che fanno tutti gli utenti in un giorno è molto più grande del numero di nuove iscrizioni)
3) la lista degli utenti è sempre in memoria, cioè il programma è sempre in esecuzione (e quindi non devi caricare la lista dal disco ogni volta che vuoi fare una ricerca); se non è così si può fare lo stesso ma dovresti usare un file per ogni utente e non so che impatto potrebbe avere questo sulla velocità del programma.

In questo caso puoi usare l'insertion sort per l'inserimento di nuovi utenti e la ricerca binaria per cercare un utente. Dato che in C non esiste l'equivalente del vector di C++ dovresti anche implementare una lista dinamica, cioè che aumenta di dimensione quando necessario, a meno che tu non abbia un'idea precisa di quanti utenti potrai mai avere al massimo.


Altrimenti ti puoi accontentare del tuo algoritmo e pulirlo un po', evitando di contare gli utenti ogni volta.

Il mio programma è soltanto una simulazione la cui traccia è molto generica, possiamo realizzarlo come vogliamo. Ovviamente se implementassi quello che dici il 30 sarebbe assicurato :-p Ho eliminato il conteggio degli utenti, effettivamente inutile.

Stavo cercando di implementare a parte quanto mi hai detto ma sono incappato in un grande dubbio. Come faccio "convivere" assieme il concetto di lista dinamica (che utilizza puntatori e malloc) con il concetto di File? Se utilizzo solo la lista dinamica gli utenti non hanno modo di rimanere in memoria alla chiusura del programma, o no? >.
Intervento di B_gin a.k.a. b_gin del 27-07-2012 ore 17:11, Padova (PD)
Nobile
Nobile

(62 interventi)
Iscritto il 14-11-2010
javoso89 ha scritto:
Stavo cercando di implementare a parte quanto mi hai detto ma sono incappato in un grande dubbio. Come faccio "convivere" assieme il concetto di lista dinamica (che utilizza puntatori e malloc) con il concetto di File? Se utilizzo solo la lista dinamica gli utenti non hanno modo di rimanere in memoria alla chiusura del programma, o no?.

(scusa se ti rispondo adesso ma ero al mare teeth.gif )

Il dubbio che ti è venuto è collegato al punto 3 della lista che ti ho fatto: se il tuo programma non è sempre in esecuzione (= in memoria), bisognerebbe leggere dal disco tutto il file con l'elenco degli utenti ogni volta che vuoi cercare o aggiungere un utente, e questo renderebbe inutile l'uso della lista ordinata per velocizzare la ricerca (perché devi comunque leggere tutti gli utenti della lista quindi tanto vale non ordinarli).
Se invece non vuoi (o non puoi) tenere sempre il programma in esecuzione, puoi fare come ho detto sempre nel punto 3: usi una lista sul disco invece che in memoria, ossia un insieme di file ("1", "2", "3", ...) ognuno con i dati di un utente, e fare la ricerca trattando ogni file come se fosse l'elemento di un array. Questa è una cosa un po' strana e in realtà di solito si usa un database, ma se è per motivi didattici lo considero un esercizio interessante.
Commenti:  Primi  «  Meno recenti  «  11 - 15 di 15
Copyright Programmazione.it™ 1999-2013. Alcuni diritti riservati. Testata giornalistica iscritta col n. 569 presso il Tribunale di Milano in data 14/10/2002. Pagina generata in 0.298 secondi.