braian
10-02-2008, 21:22
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:
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;
};
Oltre a questo pensavo di effettuare la serializzazione dei dati su file per consentire il ripristino della struttura con una funzione start() all'avvio del sistema operativo.
Per la creazione di file ho pensato a una soluzione di questo tipo:
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;
}
In questa funzione ho tralasciato però il fatto di aggiornare subito la mia struttura dati. Comunque si capisce in che modo vorrei salvare su file i dati della struttura. Altro problema che mi si presenta è quello che se nella stringa di formato o negli argomenti passati alla mia funzione si verifica un errore a quel punto avrei già scritto parte degli argomenti sul file. Quindi mi viene da pensare che sarebbe meglio crearmi prima la variabile struct filemem per memorizzare il file mentre lo elaboro ed eventualmente cancellarla in caso di errore dopo di che salvare eventualmente su file.
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
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:
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;
};
Oltre a questo pensavo di effettuare la serializzazione dei dati su file per consentire il ripristino della struttura con una funzione start() all'avvio del sistema operativo.
Per la creazione di file ho pensato a una soluzione di questo tipo:
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;
}
In questa funzione ho tralasciato però il fatto di aggiornare subito la mia struttura dati. Comunque si capisce in che modo vorrei salvare su file i dati della struttura. Altro problema che mi si presenta è quello che se nella stringa di formato o negli argomenti passati alla mia funzione si verifica un errore a quel punto avrei già scritto parte degli argomenti sul file. Quindi mi viene da pensare che sarebbe meglio crearmi prima la variabile struct filemem per memorizzare il file mentre lo elaboro ed eventualmente cancellarla in caso di errore dopo di che salvare eventualmente su file.
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