ECCEZIONE GENERATA IN LETTURA DATI DA FILE

di il
10 risposte

ECCEZIONE GENERATA IN LETTURA DATI DA FILE

Salve a tutti,
sto facendo degli esercizi sulla lettura / scrittura dati su file. Ho un problema che da alcuni giorni non riesco a risolvere...

Metto qui sotto una versione semplificata del programma che sto facendo (una rubrica) ma che replica l'errore che ho.
Essendo una versione semplificata breve è necessario che il file archivio "prova.pro" sia creato a mano... (nel completo viene creato in automatico ma questa parte funziona e l'ho lasciata perdere)

Quando vado ad eseguire il programma (con Visual Studio) l'elenco dei nomi viene prelevato dal file e stampato a video, però il programma si ferma per la generazione di una eccezione, questa sotto, e si apre il file xutility.
------
È stata generata un'eccezione: violazione di accesso in lettura.
**_Pnext** era 0xECE0BC.
------

Io non riesco però a capire cosa c'è che non va..... qualche consiglio?


#include<iostream>
#include<string>
#include<fstream>
using namespace std;

typedef struct Dato
{
	int id;
	string nome;
}Dato;

void leggi(string nomeFile)	//legge i dati dal file
{

	ifstream file(nomeFile, ios::in | ios::binary);
	if (!file)
	{
		cerr << "errore in apertura scrivi";
		exit(1);
	}
	Dato temp;
	for (int i = 0; i < 3; i++)
	{
		file.read(reinterpret_cast<char*>(&temp), sizeof(Dato));
		cout << temp.id << " - " << temp.nome << endl;
	}
}

int main()
{
	string nomeFile = "prova.pro";

		//apre il file
		fstream file(nomeFile, ios::out | ios::in | ios::binary);
		
		//se il file se non esiste
		if (!file)
		{	
			cerr << "il file non esiste e/o non può essere creato";
			exit(1);
		}
	
		Dato elenco[]=
		{
			{1,"sandro"},{2, "paolo"},{3,"marco"}
		};
		//scrive i record sul file
		for (int i = 0; i < 3; i++) file.write(reinterpret_cast<char*>(&elenco[i]), sizeof(Dato));
	
		leggi(nomeFile);
	

	return 0;
}

10 Risposte

  • Re: ECCEZIONE GENERATA IN LETTURA DATI DA FILE

    Std::string è una classe con dei puntatori interni e non puoi leggerla/scriverla su file semplicemente facendo un cast.
  • Re: ECCEZIONE GENERATA IN LETTURA DATI DA FILE

    Come ti ha detto shodan, non puoi scrivere il contenuto di un oggetto con dei puntatori interni che non valgono più quando rileggi-
    Puoi però scrivere la lunghezza e il contenuto della stringa nel file binario per ogni stringa e rileggerli ricreando le singole stringhe.
  • Re: ECCEZIONE GENERATA IN LETTURA DATI DA FILE

    In prove piu semplici ho utilizzato una struttura con int e string e non ho avuto errori. Inoltre, in questo caso, i dati vengono letti e visualizzati su schermo perche l'errore arriva dopo l'uscita dalla funzione leggi().

    in ogni modo questo errore lo posso risolvere mettendo un puntatore a char al posto della stringa?
  • Re: ECCEZIONE GENERATA IN LETTURA DATI DA FILE

    Sarebbe la stessa cosa. Per non avere problemi, la struttura dovresti dichiararla come:
    
    typedef struct Dato
    {
    	int id;
    	char nome[N];
    }Dato;
    
    dove N è un numero costante sufficiente a contenere quel che vuoi memorizzare.
    Ma perché vuoi memorizzare i dati in binario?
  • Re: ECCEZIONE GENERATA IN LETTURA DATI DA FILE

    Non ho motivi particolari, sto auto-studiando su un libro e sto facendo esercizi di apprendimento.

    Come ho scritto, l'esempio sopra è un estratto di un programma rubrica piu complesso, invece questo sotto, sempre con una struttura con dato stringa funziona. Questo l'ho fatto per capire il funzionamento della lettura / scrittura su file binario.
    Non capisco il motivo...
    
    #include <iostream>     // std::cout
    #include <fstream>      // std::ifstream
    #include <string>
    
    using namespace std;
    
    typedef struct P
    {
    	int numero;
    	string parola;
    }P;
    
    int main () 
    {
      P prova[3];
      P temp;
      string nome[3]={"sandro", "michela", "giulia"};
      
      fstream is ("reinterpret.txt", ios::out | ios::in | ios::binary ); ///ios::out | ios::in | ios::binary
      if (!is) cerr<<"errore in apertura file"<<endl;
      
      //inserisce nel file le informazioni
      for(int i=0; i<3; i++){
      	prova[i].numero=i;
      	prova[i].parola=nome[i];
      	is.write(reinterpret_cast<char*>(&prova[i]), sizeof(P));
        }
        
      //recupera e visualizza le informazioni del file
      is.seekg(0);	//rimette il puntatore del file all'inizio
      for(int i=0; i<3; i++)
      {
      	is.read(reinterpret_cast<char*>(&temp), sizeof(P));
      	cout<<temp.numero<<" "<<temp.parola<<endl;
      }
    
        int scelta=0;
        cout<<"scegliere posizione (0/2): ";
        while(cin>>scelta)
        {
        	if(scelta>=0 and scelta<=2)
        	{	//is.seekg(0);
        		long posizione= scelta*sizeof(P);
        		is.seekg(posizione, is.beg);	//posoziona il puntatore sul record da leggere
    			is.read(reinterpret_cast<char*>(&temp),sizeof(P));
    			cout<<temp.numero<<" "<<temp.parola<<endl;
    		}
        	cout<<"scegliere posizione (0/2): ";
    	}
    	
    	
       is.close();
     
      return 0;
    }
    
    
    
  • Re: ECCEZIONE GENERATA IN LETTURA DATI DA FILE

    Ti ripeto che il problema è nel valore del puntatore incluso all'interno dell'oggetto stringa.

    Questo puntatore ti dà problemi quando viene usato, ad esempio, durante la distruzione dell'oggetto stesso.
    Ed è quello che succedeva nella funzione che usavi prima in cui la distruzione della variabile di titpo struttura (locale) imponeva la distruzione delle stringhe contenute in essa.

    In questo sorgente che hai proposto, la variabile temp non viene distrutta finché sei nel ciclo di visualizzazione e quindi il valore del puntatore non influisce, ma prova ad uscire dal ciclo while per terminare il programma e vedi cosa succede.

    Le string sono oggetti che NON possono essere inclusi nelle strutture e trattate come nel C salvandole e rileggendole da file binario.

    E ovviamente tutti i puntatori NON possono essere inclusi in una struttura e salvati/riletti da un file. E mi sembra ovvio dato che un puntatore contiene un indirizzo e gli indirizzi CAMBIANO da esecuzione ad esecuzione e quindi quelli nel file NON sono validi.
  • Re: ECCEZIONE GENERATA IN LETTURA DATI DA FILE

    Sospettavo ci fosse un problema del genere... comunque ci studio un po'

    grazie per ora
  • Re: ECCEZIONE GENERATA IN LETTURA DATI DA FILE

    In questi giorni ho fatto qualche prova per capire il funzionamento di questa "benedetta" lettura/scrittura su file
    Ho seguito le tue indicazioni mettendo nella struttura un puntatore a char o un array, in entrambi i modo non ho piu errori. Però sono andato un po avanti ed ho notato una cosa che non capisco.

    Come vedi dal listato sotto ho diviso l'esecuzione in 3 funzioni distinte:
    verifica() > serve per creare il file prova.pro se non esiste
    scrivi() > scrive i dati sul file
    leggi() > legge i dati dal file

    Dalla seconda esecuzione il file è creato e scritto con i dati, quindi non lanciando la funzione scrivi (stessa cosa anche se levo verifica e scrivi) non dovrebbe cambiare niente.... e invece no!! perchè nuovamente c'è un errore di lettura della memoria nel momento in cui vado a stampare su schermo i dati col cout<<.

    Non riesco a c aprire perche... eppure le funzioni sono tutte scollegate con i singoli oggetti che si creano e si distruggono al loro interno e non c'è piu la variabile string nella struttura che da problemi col puntatore e, d'altronde, le la finz leggi() fosse scritta male l'errore sarebbe emerso anche in abbinata con la funzione scrivi().... però non va!! cosa mi sfugge??


    ciao e grazie
    
    #include<iostream>
    #include<string>
    #include<fstream>
    using namespace std;
    
    typedef struct Dato
    {
    	int id;
    	const char *nome;	//funziona
    //	char nome[10];		//funziona
    }Dato;
    
    void leggi(string nomeFile)	//legge i dati dal file
    {
    	ifstream file(nomeFile, ios::in | ios::binary);
    	if (!file)
    	{
    		cerr << "errore in apertura scrivi";
    		exit(1);
    	}
    	Dato temp;
    	for (int i = 0; i < 3; i++)
    	{
    		file.read(reinterpret_cast<char*>(&temp), sizeof(Dato));
    		cout << temp.id << " - " << temp.nome << endl;
    	}
    	file.close();
    }
    
    void scrivi(string nomeFile)
    {
    	//apre il file
    	fstream file(nomeFile, ios::out | ios::in | ios::binary);
    
    	//scrive i record sul file
    	Dato elenco[] =
    	{
    		{1,"sandro"},{2, "paolo"},{3,"marco"}
    	};
    	for (int i = 0; i < 3; i++) file.write(reinterpret_cast<char*>(&elenco[i]), sizeof(Dato));
    
    	//chiude il file
    	file.close();
    }
    void verifica(string nomeFile)
    {
    	//se il file non esiste lo crea
    	ofstream file_t(nomeFile);
    	if (!file_t)
    	{
    		cerr << "il file non esiste e/o non può essere creato";
    		exit(1);
    	}
    	file_t.close(); //chiude il file aperto in sola scrittura
     }
    
    int main()
    {
    	string nomeFile = "prova.pro";
    	
    	
    	verifica(nomeFile);
    	scrivi(nomeFile);
    	leggi(nomeFile);
    	
    	
    	return 0;
    }
    
  • Re: ECCEZIONE GENERATA IN LETTURA DATI DA FILE

    Non hai capito.
    Quando si effettua una scrittura/lettura tramite un cast la struttura non deve avere puntatori espliciti al suo interno, ne classi che ne contengano.
    
    typedef struct Dato
    {
    	int id;
    	const char *nome;	//NON funziona
    
    }Dato;
    
    Quando vai a scrivere, nel file ti viene scritto l'indirizzo del puntatore, non quello a cui punta. Conseguentemente quando vai a rileggere il file tramite il cast, nome conterrà un indirizzo spazzatura.
    Il modo corretto è :
    
    typedef struct Dato
    {
    	int id;
    	char nome[10];	//funziona
    
    }Dato; 
    
    ti piaccia o meno.
    E personalmente userei una memset() prima di leggere il file.
  • Re: ECCEZIONE GENERATA IN LETTURA DATI DA FILE

    Cosa non hai capito di quando ti ho scritto

    [B]
    E ovviamente tutti i puntatori NON possono essere inclusi in una struttura e salvati/riletti da un file.


    ??

    Il fatto è che tu non hai capito cosa è un puntatore e come funziona. Solo se torni a studiare questo argomento e lo comprendi veramente riesci a capire il problema che ha il tuo codice.

    E bada bene che l'argomento puntatori è fondamentale in c++ e ancora più in c. Non lo sottovalutare
Devi accedere o registrarti per scrivere nel forum
10 risposte