Visualizzazione dei risultati da 1 a 9 su 9
  1. #1

    c++ gestione file c like

    ragazzi non riesco a capire perchè questo programma cosi semplice non va
    qualcuno riesce ad aiutarmi?
    #include <iostream>
    #include <conio.h>
    using namespace std;


    int main() {
    int n=0,anno=0;
    struct Data {
    int giorno;
    int mese;
    int anno;
    };
    typedef struct Data DATA;
    DATA data;

    FILE* fpunt;
    fpunt = fopen("prova.dat","w");

    //scrivo
    for(n=0;n<4;n++) {
    data.giorno=n;
    data.mese=n;
    data.anno=n;
    fwrite (&data,sizeof(DATA),1,fpunt);
    }
    fclose(fpunt);

    //leggo
    fpunt = fopen("prova.dat","r");
    fread (&data,sizeof(DATA),1,fpunt);
    while (!feof(fpunt)) {
    cout << data.giorno;
    cout << " - ";
    cout << data.mese;
    cout << " - ";
    cout << data.anno;
    cout << endl;
    fread (&data,sizeof(DATA),1,fpunt);
    }
    fclose(fpunt);


    //prendo un anno da modificare
    cout << "inserisci l'anno" << endl;
    cin >> anno;
    fpunt = fopen("prova.dat","r+");
    fread (&data,sizeof(DATA),1,fpunt);
    while (!feof(fpunt)) {
    if(anno==data.anno) {
    cout << "Record da modificare: ";
    cout << data.giorno;
    cout << " - ";
    cout << data.mese;
    cout << " - ";
    cout << data.anno;
    cout << endl;
    cout << "Inserisci il giorno" << endl;
    cin >> data.giorno;
    cout << "Inserisci il mese" << endl;
    cin >> data.mese;
    cout << "Inserisci l'anno" << endl;
    cin >> data.anno;
    fseek(fpunt, 0 , SEEK_CUR);
    fwrite (&data,sizeof(DATA),1,fpunt);

    }
    fread (&data,sizeof(DATA),1,fpunt);
    }
    fclose(fpunt);


    getch();
    return 0;

    }

    Inserisco semplicemente 4 struct in un file poi le leggo.
    Successivamente chiedo di inserire un ora e voglio modificare il contenuto di quella riga.
    Ma dopo avermi chiesto i dati "modificati" va in loop, cioè mi richiede sempre gli stessi dati

  2. #2
    Non puoi modificare direttamente il file, rimpiazzando la riga. Devi riscrivere il file.
    Al momento mi viene in mente questo metodo: apri un file temporaneo, se la riga non è quella che ti interessa (cioè l'anno non è quello scelto), la scrivi pari pari nel nuovo file. Se l'anno è quello scelto, scrivi la variabile data modificata nel file temporaneo.

    Al posto del codice:

    Codice PHP:
    //prendo un anno da modificare
    cout << "inserisci l'anno" << endl;
    cin >> anno;
    fpunt fopen("prova.dat","r+");
    fread (&data,sizeof(DATA),1,fpunt);
    while (!
    feof(fpunt)) {
    if(
    anno==data.anno) {
    cout << "Record da modificare: ";
    cout << data.giorno;
    cout << " - ";
    cout << data.mese;
    cout << " - ";
    cout << data.anno;
    cout << endl;
    cout << "Inserisci il giorno" << endl;
    cin >> data.giorno;
    cout << "Inserisci il mese" << endl;
    cin >> data.mese;
    cout << "Inserisci l'anno" << endl;
    cin >> data.anno;
    fseek(fpuntSEEK_CUR);
    fwrite (&data,sizeof(DATA),1,fpunt);

    }
    fread (&data,sizeof(DATA),1,fpunt);
    }
    fclose(fpunt); 
    puoi mettere

    Codice PHP:
        //prendo un anno da modificare
        
    cout << endl <<"Inserisci l'anno: ";
        
    cin >> anno;
        
        
    fpunt fopen("prova.dat","r");
        
    FILEftemp fopen("temp.dat""w");
        
        
    fread (&data,sizeof(DATA),1,fpunt);
        while (!
    feof(fpunt)) {
            if(
    anno==data.anno) {
                
    cout << "Record da modificare: ";
                
    cout << data.giorno;
                
    cout << " - ";
                
    cout << data.mese;
                
    cout << " - ";
                
    cout << data.anno;
                
    cout << endl;
                
    cout << "Inserisci il giorno: ";
                
    cin >> data.giorno;
                
    cout << "Inserisci il mese: ";
                
    cin >> data.mese;
                
    cout << "Inserisci l'anno: ";
                
    cin >> data.anno;                        
            }    
            
    fwrite (&data,sizeof(data),1,ftemp);
            
    fread (&data,sizeof(data),1,fpunt);
        }
        
    fclose(fpunt);
        
    fclose(ftemp);
        
        if(
    remove("prova.dat") != 0)
            
    perror("[error] ");
            
        if(
    rename("temp.dat""prova.dat")!=0)
            
    perror("[error] "); 

  3. #3
    Ti invio la risposta del mio professore quando gli ho detto che per modificare una riga era necessario riscrivere il file.

    Questa è stata la mia mail:

    Salve professore, scusi il continuo disturbo ma lei è l'unico a cui posso chiedere questa cosa visto che ha preparato lei la traccia.
    La traccia è la seguente:
    La segreteria di una scuola media superiore vuole gestire l'elenco degli studenti provenienti dalla media inferiore e iscritti al primo anno di corso. L'archivio fisico di nome PrimoAn.dat, deve contenere i seguenti dati per ogni singolo studente: Codice studente (numero intero) cognome, nome, voto di diploma, lingua frequentata, classe e sezione di iscrizione.
    Il programma di gestione con modalità di accesso sequenziale deve permettere di realizzare le seguenti operazioni.
    1. Inserimento di tutti i record
    2. Modifica di un record
    3. Cancellazione di un record


    Volendo eseguire il punto 2 e il punto 3 dell'esercizio senza accedere alla tabella della segreteria nella memoria di massa (qui non è espressamente richiesto ma ho notato che nei compiti d'esame è richiesto) è lecito fare in questo modo?

    Per la modifica:
    Chiedere all'utente il codice dello studente da modificare.
    Ricercare lo studente all'interno del file
    Se lo studente è presente inserisci in una nuova struct i dati modificati di quello studente.
    Caricare dal file tutti i dati in struct caricando al posto della riga da modificare la nuova riga inserita
    Riscrivere il file utilizzando le struct precedenti
    In pratica per la gestione (C-like) dei file non esiste un modo per modificare una riga senza riscrivere il file?


    Per la cancellazione
    Chiedere all'utente il codice dello studente da cancellare.
    Caricare dal file tutti i dati in struct non caricando la riga con il codice da cancellare
    Riscrivere il file utilizzando le struct precedenti
    In pratica per la gestione (C-like) dei file non esiste un modo per cancellare una riga senza riscrivere il file?

    Quindi la limitazione per l'uso della memoria centrale sono dovute solo al momento dell'inserimento? Nel senso che al momento dell'inserimento non è lecito fare confronti (p.e. per stabilire l'utente con voto più alto ecc.)

    Questa è stata la sua risposta:

    Caro studente,

    ecco i miei suggerimenti.


    1) Anche con la programmazione C-like è possibile modificare/cancellare un singolo record (sia ad accesso sequenziale che ad accesso diretto), senza la necessità di riscrivere tutto il file.

    2) La richiesta indicata di solito nelle tracce di esame (senza utilizzare la tabella in memoria centrale) implica che non è possibile dichiarare una tabella complessiva in memoria.
    Tutte le modifiche/cancellazione dei record devono essere fatte leggendo ogni singolo record e apportando le opportune modifiche in modalità sequenziale e ad accesso diretto (ved. Slide del corso)

    3) E’ troppo semplice dichiarare una tabella in memoria centrale e modificare il record di interesse e poi modificare riscrivendo tutto il file su memoria di massa.

    e mi ha allegato questo esempio di modifica che ho cercato di sfruttare nell'esempio che ho postato ma senza risultati:

    void modifica_record(){
    FILE* fp;
    int code, nrec=0;
    student studente,temp;
    cout<<"Inserire codice studente da modificare"<<endl;
    cin>>code;

    if((fp=fopen("PrimoAn.dat","r"))==NULL){
    cout<<"Il file non esiste"<<endl;
    }
    while(fread(&studente,sizeof(studente),1,fp) && !feof(fp)){
    nrec++;
    if(studente.codice==code){
    cout<<"Il codice del record da modificare e':\t"<<studente.codice<<endl;
    cout<<"Il nome alla posizione"<<nrec<<"e':\t"<<studente.nome<<endl;
    cout<<"Il cognome alla posizione"<<nrec<<"e':\t"<<studente.cognome<<endl;
    cout<<"Il voto con cui si e' diplomato:"<<studente.voto_dip<<endl;
    cout<<"La lingua studiata e':"<<studente.lingua<<endl;
    cout<<"La classe e la sua sezione sono:"<<studente.classe<<studente.sezione<<endl;
    }
    }
    cout<<"Inserire il nome dello studente che si vuol modificare"<<endl;
    cin>>studente.nome;
    cout<<"Inserire il cognome dello studente che si vuol modificare"<<endl;
    cin>>studente.cognome;
    cout<<"Inserire il voto con cui lo studente si e' diplomato:"<<endl;
    cout<<"Premere 1 per sufficiente,2 per buono, 3 per distinto, 4 per ottimo"<<endl;
    cin>>studente.voto_dip;
    cout<<"Inserire la lingua studiata:"<<endl;
    cout<<"Premere 1 per inglese,premere 2 per tedesco e 3 per francese"<<endl;
    cin>>studente.lingua;
    cout<<"Inserire la classe d'iscrizione:"<<endl;
    cin>>studente.classe;
    cout<<"Inserire la sezione della classe di iscrizione:"<<endl;
    cin>>studente.sezione;
    fclose(fp);
    if((fp=fopen("PrimoAn.dat","r+"))==NULL){
    cout<<"Il file non esiste"<<endl;
    }
    for(int i=0;i<nrec-1;i++){
    fread(&temp,sizeof(studente),1,fp);
    }
    fseek(fp, 0 , SEEK_CUR); // per commutare da modalità lettura a modalità scrittura
    fwrite(&studente,sizeof(studente),1,fp);
    fclose(fp);
    }

    Ora tu mi dici che è necessario riscrivere il file.
    Che voleva dire il mio professore?

  4. #4
    Guarda, non ho alcuna idea di cosa voglia dire. Non opero molto con i file, ma non mi pare ci sia la possibilità di modificare un file, facendo sostituzioni a piacere. Potrei sbagliarmi comunque, magari qui sul forum c'è qualcuno che sa come fare.
    Anche perchè non mi pare proprio che il codice del tuo professore serva a qualcosa (anche qui, correggetemi se sbaglio). Oltre ad essere fatto male, secondo me, altro non fa che aggiungere la riga alla fine del file.
    Questo è il sorgente che ho creato partendo dal tuo sorgente e modificando l'ultima parte, aggiungendo il metodo proposto dal tuo prof, cercando di essere il più fedele possibile al suo testo (ho eliminato qualche stampa, qualche test sul file aperto, dato che per le nostre prove, siamo certi che il file ci sia):

    Codice PHP:
    #include <iostream>

    using namespace std;

    int main() {

        
    struct Data {
            
    int giorno;
            
    int mese;
            
    int anno;
        };
        
        
    typedef struct Data DATA;
        
    DATA data;

        
    FILEfpunt;    

        
    //scrivo
        
    fpunt fopen("prova.dat","w");    
        for(
    int n=0;n<4;n++) {
            
    data.giorno=n;
            
    data.mese=n;
            
    data.anno=n;
            
    fwrite (&data,sizeof(DATA),1,fpunt);
        }
        
    fclose(fpunt);    
        

        
    //leggo
        
    fpunt fopen("prova.dat","r");
        
    fread (&data,sizeof(DATA),1,fpunt);
        while (!
    feof(fpunt)) {
            
    cout << data.giorno;
            
    cout << " - ";
            
    cout << data.mese;
            
    cout << " - ";
            
    cout << data.anno;
            
    cout << endl;
            
    fread (&data,sizeof(DATA),1,fpunt);
        }
        
    fclose(fpunt);    

        
    // parte del professore
        
    int anno;
        
    int nrec 0;
        
    cout << "Anno: ";
        
    cin >> anno;
        
        
    fpunt fopen("prova.dat""r");
        while(
    fread(&datasizeof(DATA), 1fpunt) && !feof(fpunt))
        {
            
    nrec++;
            if(
    data.anno == anno)
            {
                
    cout << "Data trovata" << endl;
            }
        }
        
        
    cout << "Nuovo giorno: ";
        
    cin >> data.giorno;
        
    cout << "Nuovo mese: ";
        
    cin >> data.mese;
        
    cout << "Nuovo anno: ";
        
    cin >> data.anno;    
        
        
    fpunt fopen("prova.dat""r+");
        
    DATA temp;
        for(
    int i 0nreci++)
        {
            
    fread(&tempsizeof(DATA), 1fpunt);
        }
        
        
    fseek(fpunt0SEEK_CUR);
        
    fwrite(&datasizeof(DATA), 1fpunt);
        
    fclose(fpunt);    
        
    // fine parte prof
        
        
    cout << endl << endl;
        
    fpunt fopen("prova.dat","r");
        
    fread (&data,sizeof(Data),1,fpunt);
        while (!
    feof(fpunt)) {
            
    cout << data.giorno;
            
    cout << " - ";
            
    cout << data.mese;
            
    cout << " - ";
            
    cout << data.anno;
            
    cout << endl;
            
    fread (&data,sizeof(Data),1,fpunt);
        }
        
    fclose(fpunt);    

        return 
    0;

    Ho aggiunto al termine la stampa del file.
    L'ho avviato la prima volta, e mi stampa al termine il nuovo record, senza modificare alcuna linea.
    Poi ho commentato la parte relativa alla scrittura dei campi 000-111...così non mi sovrascriveva il file e avevo il campo inserito la volta precedente.
    Continuando a fare modifiche, i campi vengono aggiunti al termine.
    Tra l'altro anche guardando il codice, non vedo la parte relativa ad una presunta modifica delle righe.

    Poi ripeto, potrei sbagliarmi io
    Se hai notizie, fammi sapere che sono curioso


  5. #5
    Sai ho fatto tante prove per capire se è possibile o no.
    Ma non ne sono venuto a capo.

    Ti spiego secondo me come dovrebbe funzionare l'algoritmo (lascio stare tutta la parte dell'inserimento commento solo la parte dell'inserimento sul file)


    cout << "Anno: ";
    cin >> anno;

    fpunt = fopen("prova.dat", "r");
    while(fread(&data, sizeof(DATA), 1, fpunt) && !feof(fpunt))
    {
    nrec++;
    if(data.anno == anno)
    {
    cout << "Data trovata" << endl;
    }
    }

    tramite la variabile nrec memorizza il numero dei record prima di arrivare al record che ha come anno il corrispondente anno inserito.

    Successivamente dopo aver preso i valori modificati
    cout << "Nuovo giorno: ";
    cin >> data.giorno;
    cout << "Nuovo mese: ";
    cin >> data.mese;
    cout << "Nuovo anno: ";
    cin >> data.anno;

    "SCORRE" il file di tanti record quanti indica nrec (variabile che dovrebbe stare proprio per numero record)
    fpunt = fopen("prova.dat", "r+");
    DATA temp;
    for(int i = 0; i < nrec; i++)
    {
    fread(&temp, sizeof(DATA), 1, fpunt);
    }
    Successivamente cambia la modalità di lettura con la scrittura e il programma secondo logica dovrebbe scrivere i valori modificati in quel punto.

    fseek(fpunt, 0, SEEK_CUR);
    fwrite(&data, sizeof(DATA), 1, fpunt);
    fclose(fpunt);
    // fine parte prof

    Tuttavia questo codice sembra non funzionare o mi sbaglio?
    Ora provo a mandare un email al prof e vediamo cosa mi risponde.
    Questa è la mia interpretazione poi non so se è sbagliata.

  6. #6
    Ok allora, scusami tanto ma ho detto una sciocchezza prima.
    Poi, non so se il codice che hai postato è del professore (spero proprio di no!) ma penso che non dovresti considerarlo assolutamente perchè contiene diversi errori logici.

    Su un file ci puoi scrivere come vuoi tu, sovrascrivendo quello che c'era prima volendo.
    Mettiamo che sul tuo file hai scritto "0 - 0 - 0" e vuoi metterci "10 - 10 - 10". Puoi tranquillamente. Pero, testualmente, "10" è più lungo di "0". Dunque sovrascrivi pure quello che c'è dopo, e perdi i dati.
    Se vuoi fare quello che vuoi fare tu non puoi usare (com'è stato fatto nell'esempio del prof) file aperti in maniera testuale. Devi usare file binari, così le sue righe avranno dimensione fissa (nel tuo caso 3 campi int = 12byte sempre).

    Codice PHP:
    #include <iostream>

    using namespace std;

    int main() {

        
    struct Data {
            
    int giorno;
            
    int mese;
            
    int anno;
        };
        
        
    typedef struct Data DATA;
        
    DATA data;
        
    FILEfpunt;    
        
        
    fpunt fopen("prova.dat","wb");    
        for(
    int i 04i++) {
            
    data.giorno i;
            
    data.mese i;
            
    data.anno i;
            
    fwrite (&data,sizeof(DATA),1,fpunt);
        }
        
    fclose(fpunt);    
        
        
    fpunt fopen("prova.dat","rb");    
        while(
    fread(&datasizeof(DATA), 1fpunt) && !feof(fpunt)){
            
    cout << data.giorno << " - " << data.mese << " - " << data.anno << endl;
        }
        
    fclose(fpunt);    
        
        
    int anno;
        
    int nrec 0;
        
    cout << "Anno: ";
        
    cin >> anno;
        
        
    fpunt fopen("prova.dat""rb");
        while(
    fread(&datasizeof(DATA), 1fpunt) && !feof(fpunt))
        {                
            if(
    data.anno == anno)
            {
                
    cout << "Data trovata, nrec = " << nrec << endl;
                break; 
    //<- 1        
            
    }
            
    nrec++; //<- 2
        
    }
        
        
    cout << "Nuovo giorno: ";
        
    cin >> data.giorno;    
        
    cout << "Nuovo mese: ";
        
    cin >> data.mese;
        
    cout << "Nuovo anno: ";
        
    cin >> data.anno;    
        
        
    fpunt fopen("prova.dat""r+b");
        
    fseek(fpuntsizeof(DATA)*nrecSEEK_CUR); //<-3
        
    fwrite(&datasizeof(DATA), 1fpunt);
        
    fclose(fpunt);    
        
        
    cout << endl << endl;
        
    fpunt fopen("prova.dat","rb");    
        while(
    fread(&datasizeof(DATA), 1fpunt) && !feof(fpunt)){
            
    cout << data.giorno << " - " << data.mese << " - " << data.anno << endl;
        }
        
    fclose(fpunt);    
        
        return 
    0;

    Nota in (1) l'istruzione break (se lo trovo, non continuo a ciclare! devo fermarmi, altrimenti scorro tutto il file e scrivo sempre alla fine, come accadave nel sorgente del prof).
    La break non basta, (2) nrec++ va DOPO il test data.anno == anno, altrimenti, supponi come input anno = 0. entri nel while, fai nrec++, il test dell'if restituisce 1, avviene la break.
    Tu successivamente salti nrec = 1 campi, cioè salti giusto la linea che devi modificare, modificando la successiva.
    Nota infine tutte le "b" aggiunte nell'apertura del file, per denotare la modalità binaria.

    Un'ultima cosa, non scrivere codice come quello del solito esempio:

    Codice PHP:
      if((fp=fopen("PrimoAn.dat","r"))==NULL) {
         
    cout<<"Il file non esiste"<<endl
      }

      while(
    fread(&studente,sizeof(studente),1,fp) && !feof(fp)){
          
    /* ... */
      

    non ha senso. Ti accorgi che l'apertura non è andata a buon fine e continuo lo stesso ad operarci su? Devi gestire la situazione:

    Codice PHP:
    #include <iostream>

    using namespace std;

    int main() {

        
    FILEfp;
        if ( (
    fp fopen("nonce""r")) == NULL)
        {
            
    cerr << "Errore" << endl;
            return 
    1;
        }
        else 
        {
            
    fclose(fp);
        }
        
        return 
    0;

    per farti un esempio banale.


    edit: dimenticavo, ora sai esattamente dove andare quando devi scrivere quindi questo:

    Codice PHP:
        DATA temp;
        for(
    int i 0nreci++)
        {
            
    fread(&tempsizeof(DATA), 1fpunt);        
        }
        
        
    fseek(fpunt0SEEK_CUR); 
    diventa inutile, l'ho quindi rimpiazzato con

    Codice PHP:
        fseek(fpuntsizeof(DATA)*nrecSEEK_CUR); 

  7. #7

    grazieeeeeeeeeeeeeeeeeeeeeeee
    quindi il problema (oltre alle varie imperfezioni logiche) era nel file binario.
    Grazie mille.
    Per cancellare invece un record sempre inserendo un determinato anno cosa devo scriverci procedendo sempre nella stessa maniera?on
    Se questo è il mio file:
    dato1,dato2,dato3
    .
    .
    .daton,daton,daton riga nesima
    .
    .
    .datom,datom,datom riga mesima

    e voglio cancellare la riga n esima devo scalare tutte le righe successive? Oppure posso semplicemente eliminare quella riga con un comando?

  8. #8
    L'inserimento (non la sovrascrittura) e la cancellazione di una linea all'interno del file non penso sia possibile, e non credo di sbagliarmi questa volta. Prima di scrivere ho fatto qualche ricerca comunque e non ho trovato nulla che mi contraddicesse.

    In questo caso agirei in uno di questi due modi: creerei un file temporaneo (sulla falsariga di quanto scrissi qualche post fa) e scriverei al suo interno le righe che devo mantenere, saltando quelle da cancellare. Dopodichè cancello il file originale e rinomino il file temporaneo

    Un altro metodo è quello di marcare come cancellata la linea e farla skippare dal programma in fase di lettura. Ad esempio potrebbe essere strutturato così:

    datoa1 datob1 datoc1 //riga 1
    datoa2 datob2 datoc2 //riga 2
    .
    .
    0 0 0 // riga j
    datoaj+1 datobj+1 datocj+1 //riga j+1
    .
    .
    0 0 0 //riga k
    .
    .
    datoan datobn datocn // riga n

    0 0 0 vuol dire che la riga è cancellata.
    Puoi successivamente implementare una funzione di compattazione del file, seguendo lo schema descritto nel primo metodo per eliminare le righe marcate come cancellate.


  9. #9
    Ok, quindi quella di segnare le righe con 000 sarebbe più una cancellazione logica diciamo.
    Comunque chiederò anche questo poichè se era scritto nella traccia significa che un modo c'è.
    Manterrò il post aggiornato.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.