|
|
|
![]() |
|
Strumenti |
![]() |
#1 |
Member
Iscritto dal: Apr 2007
Messaggi: 153
|
[c] File system associativo con metadati
Il problema
Si vuole realizzare un file system associativo che consenta di accedere in maniera più flessibile a un insieme di file memorizzato su disco. Per ogni file, vengono memorizzati anche dei metadati, che ne specificano alcune proprietà arbitrarie. Per esempio, un documento di testo potrebbe avere metadati per nome dell'autore, argomento, set di caratteri usato, numero di pagine, ecc.; un file sorgente potrebbe invece avere metadati per nome dell'autore, funzionalità implementate, numero di revisione, nome del sistema a cui appartiene, versione del linguaggio di programmazione usato, esito dei test, IDE usata, ecc. Un elemento di metadati è una coppia (chiave, valore) in cui la chiave è un identificatore (nel senso classico di un carattere alfabetico seguito da una sequenza di caratteri alfanumerici), mentre il valore può essere una stringa, un numero (floating point), o una data/ora. Scopo del file system associativo è consentire di memorizzare su memoria permanente, oltre ai dati contenuti in un file, i meta-dati relativi, ed effettuare ricerche efficienti di un file basate sui valori dei metadati Realizzazione Il file system associativo deve fornire una serie di funzioni di libreria che mimino quelle della libreria standard di I/O, con l'aggiunta di opportuni parametri per assegnare i metadati a un file, modificarli, cancellarli, ed effettuare ricerche. Queste ultime possono essere di tre tipi: per uguaglianza o per sottostringa sulle chiavi di tipo stringa, per confronto numerico sulle chiavi di tipo numerico o data/ora (minore, minore uguale, uguale, maggiore o uguale, maggiore). La progettazione di questa API è parte dello sviluppo. La mia idea è quella di creare una struttura dati a llist di questo tipo: Codice:
union valore { char* stringa; float numero; int data; }; struct metadato { char* chiave; union valore val; int tipoval; struct metadato* next; }; struct filemem { char* nomefile; struct metadato* first; struct filemem * next; }; Per la creazione di file ho pensato a una soluzione di questo tipo: Codice:
int createf(const char *path,const char *mode,char* fmt,...) //funzione con numero di parametri variabile, i primi 2 servono per la fopen, il terzo è una stringa di formato per i parametri variabili. E'un errore nn passare la stringa di formato, al limite passarla vuota per non inserire metadati. Eventuali parametri in più rispetto a quelli specificati nella stringa di formato vengono ignorati. { va_list ap; //il puntatore a argomento FILE* file; //il file da creare o modificare FILE* filesave=fopen("save.sav","a"); //il file di salvataggio delle associazioni int close; int lung; char* stringa; char* sval; float fval; struct tm * t; time_t tx; int scritti; if ((file=fopen(path, mode))==NULL) { printf("errore1"); } scritti=fprintf(filesave,"%s,",path); if (scritti<0) { printf("errore 10");//trattamento errore } va_start(ap,fmt); while(*fmt!='\0') { if(isalpha(*fmt)!=0) { lung=strcspn(fmt," "); char *str=malloc(sizeof(char)*lung+1); stringa=strncpy(str,fmt,lung); stringa[lung]='\0'; if(fputs(stringa,filesave)==EOF) //scrive il nome del metadato { printf("errore2");//gestione errore in fputs } fputc(',',filesave); fmt=fmt+lung; //fmt punta al successivo formato di tipo metadato(%s,%n..) if(isspace(*fmt)==0) { printf("errore3");//trattamento errore, non c'è lo spazio dopo il nome di metadato } fmt++; if(*fmt=='%') { fmt++; switch(*fmt) { case 's': sval=va_arg(ap,char*); scritti=fprintf(filesave,"\%s,%s,",sval); if (scritti<0) { printf("errore 11"); } fmt++; break; case 'n': fval=va_arg(ap,double); scritti=fprintf(filesave,"%f,",fval); if (scritti<0) { printf("errore 12"); } fmt++; break; case 'd': t=va_arg(ap,struct tm*); tx=mktime(t); if (tx == (time_t) (-1)) { printf ("Errore! %ld\n", (long int) tx); //trattamento errore data da rivedere } scritti=fprintf(filesave,"%d/%d/%d,",t->tm_mday,t->tm_mon+1,t->tm_year+1900); if (scritti<0) { printf("errore 14"); } fmt++; break; default : printf("errore4");//trattamento errore formato sconosciuto break; } } else { printf("errore5");//gestione errore, non c'è % dopo il nome del metadato e lo spazio } } } scritti=fprintf(filesave,"\n"); if (scritti<0) { printf("errore15"); } close=fclose(filesave); if (close==EOF) { //trattamento errore } va_end(ap); return 0; } Mi chiedo poi se un approccio del genere sia giusto o sia meglio creare una "pipe" dalla mia funzione direttamente a una fprintf e poi rileggere da file e ricreare la struttura con una fscanf (sempre che questo si possa fare). HELP |
![]() |
![]() |
![]() |
#2 |
Senior Member
Iscritto dal: May 2004
Città: Londra (Torino)
Messaggi: 3692
|
La struttura dati direi che va bene.
In C non penso si possa fare tanto di meglio. Qui si inizia a capire che le classi e l'ereditarieta' potrebbero aiutare parecchio. In pratica ti si sta chiedendo di realizzare un mini-database. Per quanto riguarda la scrittura su file, non sono riuscito a capire se conti di avere un file per i "File" e uno per i "Metadati". Io almeno farei cosi'. Il gestirli separatemente avrebbe vantaggi tipo la gestione indipendente dell'entita' "File" e della relazione "Metadato". Il nome del file sarebbe la chiave primaria di ciascun file. La coppia "Nome de file" + "Nome del metadato" sarebbe invece la chiave primaria di ciascun metadato. Il file dei "File" avrebbe quindi l'elenco di ciascun file, ciascuno con la chiave (nome) e le sue caratteristiche richieste (ma ce ne sono?) Il file dei "Metadati" avrebbe l'elenco dei metadati. Ciascuno con la chiave (nome del file, nome del metadato) e a seguire su ciascuna riga ci sarebbero le caratteristiche del metadato, nel formato che si preferisce. Un opportuno campo (basta un carattere) iniziale su ciascuna riga potrebbe stare ad indicare se la riga e' cancellata o meno (cosi' cancelliamo in fretta). L'inserimento dovrebbe essere facile (occhio alle violazioni di chiave), sempre in coda al file. La cancellazione pure. Per l'aggiornamento procederei con una cancellazione e poi un nuovo inserimento. Gli inserimenti proporrei di farli piu' atomici possibile. Scrivi la riga in un opportuno buffer di memoria, e poi la salvi tutta insieme in un comando solo. Questo ti consiglio di farlo indipendentemente dalla soluzione. Se ti piace si puo' proseguire, senno' cerca pure tranquillamente un'altra strada. Come detto programmare e' un processo creativo, nulla e' legge. Ci sono pero' dipinti belli e dipinti brutti. Questo non mi sembra tanto brutto. _____________ PS: Mi e' venuto in mente un modo "cattivo" per barare malamente. Se e' un esercizio pero' conta che i prof. normalmente non apprezzano chi bara. Se pero' l'apprezzano e' li' che prendi la lode.
__________________
Se pensi che il tuo codice sia troppo complesso da capire senza commenti, e' segno che molto probabilmente il tuo codice e' semplicemente mal scritto. E se pensi di avere bisogno di un nuovo commento, significa che ti manca almeno un test. |
![]() |
![]() |
![]() |
#3 |
Member
Iscritto dal: Apr 2007
Messaggi: 153
|
Intanto grazie per la risposta, per la serializzazione avrei pensato di utilizzare un solo file di salvataggio per gestire file e metadati insieme.
Questo anche perchè le uniche informazioni che devo salvare riguardanti i file sono appunto i metadati. Da quello che mi dici e come pensavo dovrei prima memorizzare tutti i nomi e tipi di metadati in una stringa fino ad avere controllato la correttezza della stringa di formato e i reltivi argomenti prima di copiare su file in modo da non scrivere prima di trovare errori (ATOMICITA') o comunque in altro modo simile. Vorrei piuttosto sapere se possible cosa ne pensi della funzione in se, nel senso se ti pare giusto che effettui io controlli sulla stringa di formato e argomenti come faccio oppure se vedi possibile in qualche altro modo che al momento vedo oscuro, di creare una pipe tra la mia funzione e una fprintf per scrivere direttamente i dati su file e utilizzare una fscanf per ricaricarli. Il tutto in modo da ripulire un po' il codice da variabili e per far gestire eventuali errori direttamente dalle suddette funzioni ![]() |
![]() |
![]() |
![]() |
#4 | |
Senior Member
Iscritto dal: May 2004
Città: Londra (Torino)
Messaggi: 3692
|
Quote:
Il caricarli con la fscanf subito non l'ho capito. Ma l'esercizio non consta nel costruire una libreria di supporto ai metadati, ma su file? Non penso che tu possa considerare di averli sia in memoria che su file. L'esercizio sarebbe quello di scrivere i metadati su file, realizzando le funzioni insert/delete/update E poi di andarli a cercare e leggere sempre da file quando richiesto... Non mi servirebbe la fscanf subito, o no? Ma forse ho capito male. Resta che il metodo "baro" mi ispira sempre di piu'...
__________________
Se pensi che il tuo codice sia troppo complesso da capire senza commenti, e' segno che molto probabilmente il tuo codice e' semplicemente mal scritto. E se pensi di avere bisogno di un nuovo commento, significa che ti manca almeno un test. |
|
![]() |
![]() |
![]() |
#5 |
Member
Iscritto dal: Apr 2007
Messaggi: 153
|
Le operazioni fondamentali richieste sono quelle appunto di crazione di file attribuendogli i metadati, di modifica dei metadati associati a un file e di ricerca di file basata su condizioni logiche sui metadati.
Io immaginavo di tenere i dati memorizzati sia su file che su una struttura dati (tutta la struttuta del primo messaggio) per i seguenti motivi: -il file per la consistenza e quindi il poter ritrovare i metadati associati ai file anche dopo la chiusura e il riavvio del sistema operativo; -la struttura per velocizzare le operazioni di ricerca che richiedono tempo lineare sui metadati. Il la fscanf imaginavo che fosse utilizzabile per caricare i dati dal file alla struttura, magari con qualche meccanismo particolare tipo salvare su un altro file, quando trasferisco i dati dalla struttura al file di salvataggio, i tipi di formato contenuti nel file di salvataggio ovvero avere sull' altro file la stringa di formato da passare alla fscanf ![]() cosa intendi per metodo baro? |
![]() |
![]() |
![]() |
#6 | |||
Senior Member
Iscritto dal: May 2004
Città: Londra (Torino)
Messaggi: 3692
|
Quote:
Se pensi che l'esercizio lo permetta allora sei a posto. Quote:
Per intendere, quando p.es. inserisci, inseirisci sia sul file che sulla liste di strutture in memoria. Nessuna fscanf. Se sia l'inserimento che l'aggiornamento li fai sempre in append, al fondo del file, non avrai problemi di lunghezza variabile di record. Quote:
Es: pippo.txt e' il file, pippo.mtd e' il file associato di metadati. Niente di nuovo e di inventato... e' gia' stato fatto altre volte in passato. Ma appunto non so se sia accettabile.
__________________
Se pensi che il tuo codice sia troppo complesso da capire senza commenti, e' segno che molto probabilmente il tuo codice e' semplicemente mal scritto. E se pensi di avere bisogno di un nuovo commento, significa che ti manca almeno un test. |
|||
![]() |
![]() |
![]() |
#7 |
Member
Iscritto dal: Apr 2007
Messaggi: 153
|
ti ringrazio della pazienza che mi hai dedicato, un ultima cosa, secondo la specifica le funzioni in caso di errore devono stampare su STANDARD ERROR e non su stderr. Che vuol dire?
|
![]() |
![]() |
![]() |
#8 |
Senior Member
Iscritto dal: May 2004
Città: Londra (Torino)
Messaggi: 3692
|
Non lo so. So cos'e' STDERR, ma non cosa sia STANDARD ERROR, ma come detto sono anni che non scrivo una riga di C puro.
Sotto windows oggi si scrive comunemente sull'event log...
__________________
Se pensi che il tuo codice sia troppo complesso da capire senza commenti, e' segno che molto probabilmente il tuo codice e' semplicemente mal scritto. E se pensi di avere bisogno di un nuovo commento, significa che ti manca almeno un test. |
![]() |
![]() |
![]() |
#9 |
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
stderr è l'abbreviazione di standard error...
|
![]() |
![]() |
![]() |
#10 | |
Senior Member
Iscritto dal: May 2004
Città: Londra (Torino)
Messaggi: 3692
|
Si, ma se le specifiche dicono
Quote:
__________________
Se pensi che il tuo codice sia troppo complesso da capire senza commenti, e' segno che molto probabilmente il tuo codice e' semplicemente mal scritto. E se pensi di avere bisogno di un nuovo commento, significa che ti manca almeno un test. |
|
![]() |
![]() |
![]() |
#11 |
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Davvero strano...boh...
|
![]() |
![]() |
![]() |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 01:39.