Newsgroup: it.comp.lang.c
Titolo: C e gestione dei file

Salve,
 
devo gestire un file di testo appendendo un record se non esiste, 
aggiornando un campo contatore se il record esiste. Supponiamo che la 
ricerca sia effettuata sul campo Codice Fiscale.
 
Francesco


Uhm, un buon esercizio..
Se hai scritto del codice che non ti funziona postalo pure con i tuoi
dubbi in merito.
Ciao!


Mi associo. Contribuirò anch'io alla buona riuscita dell'esercizio.


In effetti non è un esercizio, mi stavo divertendo a scrivere dei 
programmini CGI. 
 
Francesco

 Francesco
 
Bene! Allora buon divertimento. Se qualcosa dovesse metterti tra te e 
l'orgasmo che vorresti raggiungere con questo tuo nuovo gioco, non 
preoccuparti: qui troverai un mucchio di gente in grado di appianarti la 
strada verso la gioia ma, ti prego, dicci che strada hai intrapreso, 
magari postando degli esempi che ci chiarifichino i tuoi desideri, così 
potremo indirizzarti verso l'amplesso estremo.


In questo caso chi sono io per toglierti il divertimento? :-)
Giusto due suggerimenti al volo se parti da zero o quasi...
Visto che parli di "record" immagino tu conosca linguaggi tipo basic o
fortran: fosse questo il caso sappi che a differenza di questi
linguaggi non esiste un sistema di accesso ai file a record; lo
standard definisce la scrittura binaria o testuale - quale ti possa
essere più utile dipende dai casi. Se ci dici cosa vuoi realizzare
magari ti possiamo suggerire la strada più conveniente.
Nel caso invece tu provenga dal mondo dei database, tipo plsql, sappi
che non esiste un layer trasparente per la permanenza dei dati, quindi
load/store/search vanno fatti "a mano".
Nel caso invece, visto che chiedi del CGI, tu conosca il PERL, non hai
scuse: scrivi il codice e basta! :-D
Ciao!

ops... pensavo fossi indaffarato e mi sono permesso...

 ops... pensavo fossi indaffarato e mi sono permesso...
 
Spero tu, come invece dicono gli headers, non ti rispondessi a me,
altrimenti.. boh! XD
Ciao!


Ecco il mio codice, in effetti devo fare un semplice programma di 
statistiche ad un sito web. Ma il discorso era analogo a quanto da me 
scritto nel mio precedente messaggio.
 
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#define IPFILE "./data/ipstat.txt"
#define BROWSERSTAT "./data/browsers.txt"
typedef enum{false,true} boolean;
boolean existfile(char *filename);
int main()
{
boolean trovato=false;
FILE *ipstat; // File statistiche per IP
FILE *browserstat; // File statistiche per Browser
char *ip,*browser,*s_ip,*s_br;
int c=0;
//ipstat=fopen("ipstat.txt","r");
//browserstat=fopen("browsers.txt","r");
ip=(char*)malloc(15*sizeof(char));
browser=(char*)malloc(80*sizeof(char));
s_ip=(char*)malloc(15*sizeof(char));
s_br=(char*)malloc(80*sizeof(char));
strcpy(ip,getenv("REMOTE_ADDR"));
strcpy(browser,getenv("HTTP_USER_AGENT"));
printf("Content-type: text/html\n\n");
printf("<HTML>");
printf("<HEAD>");
printf("<TITLE>Ip e Browser utilizzati</TITLE>");
printf("</HEAD>");
printf("<BODY>");
printf("ip=%s browser=%s\n",ip,browser);
printf("</BODY>");
printf("</HTML>");
// Se il file non esiste, lo crea
if(!existfile(IPFILE))
{
ipstat=fopen(IPFILE,"w+");
}
//chmod(filename,i);
while(!feof(ipstat) && trovato==false)
{
 fscanf(ipstat,"%15s %d",s_ip,&c);
 if(strcmp(ip,s_ip)==0) // Indirizzo IP trovato
  {
  c++;
 //printf("c=%d\n",c);
 fclose(ipstat);
 // Riapre il file in modalitÃ  scrittura
 ipstat=fopen("ipstat.txt","r+");
  fprintf(ipstat,"%15s %d\n",s_ip,c);
  trovato=true;
  }
}
 fclose(ipstat);
if(trovato==false)
  {
    ipstat=fopen("ipstat.txt","a");
   c=1;
   fprintf(ipstat,"%15s %d\n",ip,c);
  }
/*
trovato=false;
c=0;
while(!feof(browserstat) && trovato==false)
{
 fscanf(browserstat,"%15s %d",&s_br,&c);
 if(strcmp(browser,s_br)==0)
  {
  c++;
  fprintf(browserstat,"%15s %d\n",s_br,c);
  trovato=true;}
  }
 if(trovato==false)
  {
   c=1;
   fprintf(browserstat,"%15s %d\n",browser,c);
  }
fclose(ipstat);
fclose(browserstat);*/
/*
printf("Content-type: text/html\n\n");
printf("<HTML>");
printf("<HEAD>");
printf("<TITLE>Ip e Browser utilizzati</TITLE>");
printf("</HEAD>");
printf("<BODY>");
printf("ip=%s browser=%s\n",ip,browser);
printf("</BODY>");
printf("</HTML>");*/
return 0;
}
// Determina l'esistenza di un file
boolean existfile(char *filename)
{
    FILE *fexists;
    boolean exists=false;
    fexists=fopen(filename,"r");
    exists=(fexists!=NULL);
    fclose(fexists);
    return (exists);
}
 


 
Allora... prima le cose di concetto:
- IMPORTANTE: se sei in ambiente CGI devi fare un lock del file in
apertura, altrimenti una seconda istanza del processo potrebbe leggere/
scrivere in mezzo all'operazione di un processo precedente.
- In caso di errore devi fare in modo che il processo non muoia, pena
l'abort della pagina per l'utente: metti controlli su qualsiasi cosa
potrebbe fallire; meglio un hit non ricevuto che una pagina non
restituita.
- Per array piccoli non allocare dinamicamente, ma statico: utilizza
poi funzioni che controllano la dimensione dei buffer per evitare
overrun.
- Esistono modi migliori per fare quello che vuoi con specifiche
syscall di sistema, a seconda dell'ambiente in cui ti trovi, ma per
questo lasciamo correre visto che non siamo nello NG giusto ;)
 
A parte questo praticamente ci sei, tieni duro! :-)
Ciao!

 scritto nel mio precedente messaggio.
 
usa un db.
se non vuoi scomodare roba grossa (postgresql,...) ritieniti libero di
usare SQLite.
 
Ciao Jack
-- 
Yoda of Borg am I! Assimilated shall you be! Futile resistance is, hmm?

Ciao,
ad ora ho avuto occasione di leggere le prima 2 risposte e ti dirò... 
hanno ragione entrambi. Se è un CGI che intendi scrivere hai/avete 
scelto la strada meno piana perché in un ambiente multi-utente questi 
processi andrebbero serializzati. Ha ragione Jack suggerendoti di usare 
un DB perché in questo caso della serializzazione se ne occuperebbe il 
server che lo amministra ed ha pure ragione FtM mettendoti in guardia 
sulle eventuali collisioni. In sostanza questi CGI vanno molto bene solo 
per comporre una pagina acquisendo informazioni in giro per i dischi ma 
scrivere è un'altra faccenda. Quindi, valuta molto attentamente i loro 
consigli. Se, però, il tuo problema è solo realizzare la funzione che si 
occupa di produrti un file con le occorrenze mentre la serializzazione 
sarà un problema che affronterai in seguito, allora credo che 
l'approccio che hai mostrato sia quello corretto. Purtroppo, proprio 
come  ti è stato detto, il C non aiuta molto in questo tipo di problemi 
e bisogna (spesso 'sigh...') sopperire alla sua elasticità con la 
precisione; in particolare in questi casi. A parte tutto ciò che ti è 
stato fatto notare, nel tuo esempio manchi parecchio... d'orientamento 
quando scrivi/leggi il tuo file. Ti faccio un esempio: quando trovi un 
elemento già presente e ne incrementi il contatore, dovresti andarlo poi 
a sostituire a quello vecchio ma col puntatore al file (od al suo 
stream) ormai, avendolo letto, sei andato oltre e quindi per 
sovrascriverlo dovresti prima tornare indietro fino al punto in cui ti 
trovavi prima della lettura. Non sono riuscito ad aggiustare ciò che hai 
postato ma mi sono permesso di scriverti un esempio di come mi sarei 
approcciato al tuo problema. E' solo una bozza ma vedrai che verro 
anch'io tempestato di obiezioni; però funziona ed il file che produce è 
visualizzabile con un semplice editor. Inoltre è facilmente riadattabile 
per altre occasioni. Spero che sia di tuo interesse:
 
#include <stdio.h>
#include <memory.h>
 
int  main(int, char *[]);
void RecReset(char [], const int);
 
int main(int ac, char *av[])
{
     FILE *fp;
     const char IpFile[] = "./ipstat.txt";
     const int  IpHdrLen = sizeof "000.000.000.000 ";
     const int  NumLen = sizeof "000000000";
     const int  RecLen = IpHdrLen +  NumLen + 1;
     const char *OorC[] = {"r+", "w+"};
     const int OCsz = ((sizeof OorC) / (sizeof OorC[0]));
     char Rec[RecLen];
     char *IpPos = Rec, *CntPos = Rec + IpHdrLen;
     char *ip = "192.168.1.1";
     int found = ~0, Cnt, i, ipLen;
 
     if(ac > 1)
     {
         ip = av[1];
     }
     ipLen = strlen(ip);
 
 
     for(i = 0; i < OCsz; i++)
         if((fp = fopen(IpFile, OorC[i])) != (FILE *)NULL)
             break;
 
     if(fp == (FILE *)NULL)
         return 1;
 
     fseek(fp, 0L, SEEK_SET);
 
     while(fread(Rec, RecLen, 1, fp) > 0)
     {
         if(!strncmp(ip, IpPos, ipLen))
         {
             Cnt = 0;
             sscanf(CntPos, "%d", &Cnt);
             CntPos[sprintf(CntPos, "%d", Cnt + 1)] = ' ';
             fseek(fp, -(long)RecLen, SEEK_CUR);
             fwrite(Rec, RecLen, 1, fp);
             found = !found;
             break;
         }
     }
     if(found && feof(fp))
     {
         RecReset(Rec, RecLen);
         IpPos[sprintf(IpPos, "%s", ip)] = ' ';
         CntPos[sprintf(CntPos, "%d", 1)] = ' ';
         fwrite(Rec, RecLen, 1, fp);
     }
     fclose(fp);
     return 0;
}
 
void RecReset(char rec[], const int rlen)
{
     memset(rec, ' ', rlen);
     rec[rlen - 1] = '\n';
}
 
Come puoi notare dal sorgente, cataloga un n.ip di default ma puoi 
passargliene di alternativi da linea comando. Visualizza il file 
prodotto per verificare i risultati.
 
NB:
Mi aspetto un n.ip e non controllo che effettivamente lo sia.