Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 11
  1. #1

    [C++]Implementazione programma file accesso diretto

    Ciao, ho un problema nell'inserimento e nella visualizzazione di dati da un file ad accesso diretto. In pratica quando visualizzo i dati il programma va in errore logico(non sempre). A volte mi visualizza gli stessi dati due volte.
    Inoltre la funzione getline(cin, tool.note) non mi fa inserire la stringa e salta l'istruzione. Riporto il codice:

    codice:
    /*
     * ferramenta.h
     *
     * 
     */
    
    #ifndef FERRAMENTA_H_
    #define FERRAMENTA_H_
    
    #include <string>
    using std::string;
    
    struct Record{
    	int n_id;
    	string nome;
    	int qnt;
    	float costo;
    	string note;
    };
    
    void inizializza_file(char*);
    void inserisci_attrezzo(char*);
    void leggi_attrezzi(char*);
    
    etc...
    codice:
    /*
     * ferramenta.cpp
     *
     *  
     */
    
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <iomanip>
    #include "ferramenta.h"
    
    using namespace std;
    
    void inizializza_file(char* name1){
    	Record empty={0, "", 0, 0.0, ""};
    	ofstream f(name1, ios::out);
    	if(!f){
    		cout << "\nIl file non e' stato creato!\n";
    		return;
    	}
    	for(int i=0;i<100;i++)
    		f.write(reinterpret_cast<const char*>(&empty), sizeof(Record));
    	f.close();
    }
    
    void inserisci_attrezzo(char* name1){
    	Record tool;
    	cout << "\nInserisci numero identificativo attrezzo: ";
    	cin >> tool.n_id;
    	cout << "Inserisci nome (usa il carattere di linea per lo spazio): ";
    	cin >> tool.nome;
    	cout << "Inserisci quantita': ";
    	cin >> tool.qnt;
    	cout << "Inserisci costo: ";
    	cin >> tool.costo;
    	cout << "Inserisci note: ";
            getline(cin, tool.note); 
    	ofstream f(name1, ios::ate);
    	if(!f){
    		cout << "\nIl file non e' stato aperto!\n";
    		return;
    	}
    	f.seekp((tool.n_id-1)*sizeof(Record));
    	f.write(reinterpret_cast<const char*>(&tool), sizeof(Record));
    	f.close();
    }
    
    void leggi_attrezzi(char* name1){
    	Record object;
    	cout << "\n\n" << setiosflags(ios::left) << setw(10) << "N. Record" << setw(25) << "Nome" << setw(10) << "Quantita'" <<
    			setw(10) << "Costo" << setw(50) << "Note";
    	ifstream f(name1, ios::in);
    	if(!f){
    		cout << "\nIl file non e' stato aperto!\n";
    		return;
    	}
    	while(f && !f.eof()){
    		f.read(reinterpret_cast<char*>(&object), sizeof(Record));
    		if(object.n_id!=0)
    			stampa_attrezzo(object);
    	}
    	f.close();
    	cout << "\n\n";
    }
    Per favore aiutatemi :118:

  2. #2
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    C'è un grosso errore logico: non puoi usare una struttura contenente classi (la std::string in questo caso) e sperare che i dati si preservino dopo una brutale conversione a char* con un cast.
    Per fare una cosa del genere, i campi della struttura devono essere tipi base, non classi.
    Quindi:
    codice:
    const int MAX_NOME = 128;
    const int MAX_NOTE = 512;
    
    struct Record{
    	char note[512];
    	char nome[128];
    	int n_id;
    	int qnt;
    	float costo;
    };
    
    
    void inserisci_attrezzo(char* name1){
    	Record tool;
    	cout << "\nInserisci numero identificativo attrezzo: ";
    	cin >> tool.n_id;
    	cout << "Inserisci nome: ";
    
            std::string line;
            // getline acquisisce anche gli spazi e scarta lo \n che rimarrebbe nel buffer di input
            getline(cin,line);
            memset(tool.nome,0,MAX_NOME);
            strncpy(tool.nome,line.c_str(),std::min<int>(line.size(),MAX_NOME-1));
    	
    	cout << "Inserisci quantita': ";
    	cin >> tool.qnt;
    	cout << "Inserisci costo: ";
    	cin >> tool.costo;
    	cout << "Inserisci note: ";
    
            // getline acquisisce anche gli spazi e scarta lo \n che rimarrebbe nel buffer di input
            getline(cin,line);
            memset(tool.nome,0,MAX_NOTE);
            strncpy(tool.note,line.c_str(),std::min<int>(line.size(),MAX_NOTE-1));
    
    	ofstream f(name1, ios::ate);
    
    	if(!f){
    		cout << "\nIl file non e' stato aperto!\n";
    		return;
    	}
    	f.seekp((tool.n_id-1)*sizeof(Record));
            // Adesso la scrittura o leggere la struttura in questo
            // modo è safe.
    	f.write(reinterpret_cast<const char*>(&tool), sizeof(Record));
    	f.close();
    }
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  3. #3
    A dire la verità viene convertito in char* l'indirizzo di memoria del record che devo inserire nel file.
    Comunque, io avevo pensato che l'errore sta nell' utilizzare le string, che sono classi la cui dimensione non è fissata a priori, in un record che nel file ad accesso diretto deve avere una dimensione fissa. Mi dite se questo ragionamento è corretto?

    Inoltre mi spiegate perchè getline(cin,string) non mi permette di inserire la stringa? Io la devo inserire in un record istanziato all'interno della funzione, quindi la lunghezza fissa del record non c'entra in questo caso...

  4. #4
    Volevo chiedere anche perchè nè la versione globale di getline nè la funzione get per gli array di char mi fanno inserire la stringa. Scusate per il doppio post.

  5. #5
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    [QUOTE]Originariamente inviato da blackcat90
    Comunque, io avevo pensato che l'errore sta nell' utilizzare le string, che sono classi la cui dimensione non è fissata a priori, in un record che nel file ad accesso diretto deve avere una dimensione fissa. Mi dite se questo ragionamento è corretto?
    [QUOTE]
    Si.

    Inoltre mi spiegate perchè getline(cin,string) non mi permette di inserire la stringa? Io la devo inserire in un record istanziato all'interno della funzione, quindi la lunghezza fissa del record non c'entra in questo caso...
    In realtà non è la std::string il problema. Il problema sono le istruzioni cin >> qualcosa che non tolgono il carattere [n]\n[/b] alla fine. Questo rimane nel buffer e la getline pensa che l'input sia già finito.
    Per la cronaca, cin è sempre stato una rogna da gestire bene.
    codice:
    	Record tool;
    	cout << "\nInserisci numero identificativo attrezzo: ";
    	cin >> tool.n_id;
            cin.sync(); // risicronizza il buffer interno e toglie il carattere '\n' rimasto.
    	cout << "Inserisci nome: ";
    
            std::string line;
            // getline acquisisce anche gli spazi e scarta lo \n che rimarrebbe nel buffer di input
            getline(cin,line);
            memset(tool.nome,0,MAX_NOME);
            strncpy(tool.nome,line.c_str(),std::min<int>(line.size(),MAX_NOME-1));
    	
    	cout << "Inserisci quantita': ";
    	cin >> tool.qnt;
            cin.sync();
    	cout << "Inserisci costo: ";
    	cin >> tool.costo;
            cin.sync();
    	cout << "Inserisci note: ";
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  6. #6
    Ciao, grazie per le spiegazioni.
    Riprendo la discussione perchè il programma non mi fa aprire un file sia in input che in output.

    codice:
    /*
     * main.cpp
     *
     *
     */
    
    #include <iostream>
    #include <fstream>
    #include <stdlib.h>
    #include "ferramenta.h"
    
    using namespace std;
    
    int main(){
    	int m_opt;
    	fstream f;
    	cout << "Programma di test ferramenta\n\n\n";
    	f.open("hardware.dat", ios::in | ios::out | ios::binary);
    	if(!f){
    		cerr << "\nFile non creato!\n";
    		system("PAUSE");
    		exit(1);
    	}
    
    ecc...
    Il programma stampa "File non creato" e termina. Invece se lo apro solo in modalità input o output funziona.
    Inoltre se il file già esiste il programma lo apre in doppia modalità, ma ci sono degli errori di lettura e scrittura su file.
    :074: non capisco...

  7. #7
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Se lo apri con ios::in | ios:ut il file deve già esistere (ios::binary è ininfluente).
    Poi cosa ci sia scritto dentro dipende da te. Il codice è sempre quello postato prima?
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  8. #8
    Il programma non funziona, quando vado a fare la lettura da file va in loop.

    Ecco il codice:

    codice:
    /*
     * ferramenta.h
     *
     * 
     */
    
    #ifndef FERRAMENTA_H_
    #define FERRAMENTA_H_
    
    using std::fstream;
    
    struct Record{
    	int n_id;
    	int qnt;
    	float costo;
    	char nome[30];
    	char note[80];
    };
    
    Record record_vuoto();
    void inizializza_file(fstream& );
    void inserisci_attrezzo(fstream& );
    void leggi_attrezzi(fstream& );
    void stampa_attrezzo(const Record& );
    void elimina_attrezzo(fstream& );
    void aggiorna_attrezzo(fstream& );
    
    #endif /* FERRAMENTA_H_ */
    codice:
    /*
     * ferramenta.cpp
     *
     * 
     */
    
    #include <iostream>
    #include <fstream>
    #include <string.h>
    #include <iomanip>
    #include "ferramenta.h"
    
    using namespace std;
    
    void inizializza_file(fstream& f){
    	Record empty=record_vuoto();
    	f.seekp(0);
    	for(int i=0;i<100;i++)
    		f.write(reinterpret_cast<const char*>(&empty), sizeof(Record));
    	f.sync();
    }
    
    void inserisci_attrezzo(fstream& f){
    	Record tool;
    	cout << "\nInserisci numero identificativo attrezzo: ";
    	cin >> tool.n_id;
    	cout << "Inserisci nome: ";
    	cin.sync();
    	cin.getline(tool.nome, 30);
    	cout << "Inserisci quantita': ";
    	cin >> tool.qnt;
    	cout << "Inserisci costo: ";
    	cin >> tool.costo;
    	cout << "Inserisci note: ";
    	cin.sync();
    	cin.getline(tool.note, 80);
    	f.seekp((tool.n_id-1)*sizeof(Record));
    	f.write(reinterpret_cast<const char*>(&tool), sizeof(Record));
    	f.sync();
    }
    
    void leggi_attrezzi(fstream& f){
    	Record object;
    	cout << "\n\n" << setiosflags(ios::left) << setw(10) << "N. Record" << setw(25) << "Nome" << setw(10) << "Quantita'" <<
    			setw(10) << "Costo" << setw(50) << "Note" << "\n";
    	f.seekg(0);
    	f.read(reinterpret_cast<char*>(&object), sizeof(Record));
    	while(!f.eof()){
    		if(object.n_id!=0)
    			stampa_attrezzo(object);
    		f.read(reinterpret_cast<char*>(&object), sizeof(Record));
    	}
    	f.sync();
    	cout << "\n\n";
    }
    
    void stampa_attrezzo(const Record& r){
    	cout << setiosflags(ios::left) << setw(10) << r.n_id << setw(25) << r.nome << setw(10) << r.qnt <<
    			setw(10) << setiosflags(ios::fixed|ios::showpoint) << setprecision(2) << r.costo << setw(50) << r.note << "\n";
    }
    
    void elimina_attrezzo(fstream& f){
    	Record remove;
    	Record empty=record_vuoto();
    	int id;
    	cout << "\nInserisci il codice identificativo dell' attrezzo di cui vuoi controllare la quantita': ";
    	cin >> id;
    	f.seekg((id-1)*sizeof(Record));
    	f.read(reinterpret_cast<char*>(&remove), sizeof(Record));
    	if(remove.n_id==0){
    		cout << "L'attrezzo non esiste nell'elenco!\n";
    		return;
    	}
    	if(remove.qnt==0){
    		f.seekp((remove.n_id-1)*sizeof(Record));
    		f.write(reinterpret_cast<const char*>(&empty), sizeof(Record));
    		cout << "Oggetto mancante eliminato dall'elenco.\n";
    	}else cout << "Oggetto presente in magazzino!\n";
    	f.sync();
    }
    
    void aggiorna_attrezzo(fstream& f){
    	Record temp;
    	int id;
    	int opt;
    	cout << "\nInserisci numero identificativo dell'oggetto da aggiornare: ";
    	cin >> id;
    	f.seekg((id-1)*sizeof(Record));
    	f.read(reinterpret_cast<char*>(&temp), sizeof(Record));
    	if(temp.n_id==0){
    		cout << "Attrezzo non presente nell'elenco!\n";
    		return;
    	}
    	cout << "Vuoi cambiare il nome?(Se vuoi cambiarlo inserisci 0): ";
    	cin >> opt;
    	if(opt==0){
    		cout << "Inserisci nome: ";
    		cin.sync();
    		cin.getline(temp.nome, 30);
    	}
    	cout << "Vuoi cambiare la quantita'?(Se vuoi cambiarla inserisci 0): ";
    	cin >> opt;
    	if(opt==0){
    		cout << "Inserisci quantita': ";
    		cin >> temp.qnt;
    	}
    	cout << "Vuoi cambiare il costo?(Se vuoi cambiarlo inserisci 0): ";
    	cin >> opt;
    	if(opt==0){
    		cout << "Inserisci costo: ";
    		cin >> temp.costo;
    	}
    	cout << "Vuoi cambiare le note?(Se vuoi cambiarle inserisci 0): ";
    	cin >> opt;
    	if(opt==0){
    		cout << "Inserisci note: ";
    		cin.sync();
    		cin.getline(temp.note, 80);
    	}
    	cout << "Aggiornamento in corso . . .\n";
    	f.seekp((temp.n_id-1)*sizeof(Record));
    	f.write(reinterpret_cast<const char*>(&temp), sizeof(Record));
    	f.sync();
    	cout << "Aggiornamento completato.\n";
    }
    
    Record record_vuoto(){
    	Record r;
    	r.n_id=0;
    	r.qnt=0;
    	r.costo=0.0;
    	memset(r.nome, 0, 30);
    	memset(r.note, 0, 80);
    	return r;
    }
    codice:
    /*
     * main.cpp
     *
     * 
     */
    
    #include <iostream>
    #include <fstream>
    #include <stdlib.h>
    #include "ferramenta.h"
    
    using namespace std;
    
    int main(){
    	int m_opt;
    	fstream f;
    	cout << "Programma di test ferramenta\n\n\n";
    	f.open("hardware.dat", ios::out);
    	if(!f){
    		cerr << "\nFile non creato!\n";
    		system("PAUSE");
    		exit(1);
    	}
    	f.close();
    	f.open("hardware.dat", ios::in | ios::ate | ios::binary);
    	if(!f){
    		cerr << "\nFile non creato!\n";
    		system("PAUSE");
    		exit(1);
    	}
    	cout << "Inizializzazione file . . .\n";
    	inizializza_file(f);
    	cout << "Inizializzazione completata.\n";
    	do{
    		cout << "\n\n\nScegli un'opzione:\n1)Inserisci attrezzo nel file.\n2)Elenca attrezzi." <<
    				"\n3)Elimina attrezzo non presente in magazzino.\n4)Aggiorna dati attrezzo.\n5)Esci." <<
    				"\nInserisci opzione: ";
    		cin >> m_opt;
    		switch(m_opt){
    		case 1:{
    			inserisci_attrezzo(f);
    			break;
    		}
    		case 2:{
    			leggi_attrezzi(f);
    			break;
    		}
    		case 3:{
    			elimina_attrezzo(f);
    			break;
    		}
    		case 4:{
    			aggiorna_attrezzo(f);
    			break;
    		}
    		case 5:{
    			break;
    		}
    		default:{
    			cout << "Opzione non valida!\n";
    			break;
    		}
    		}
    	}while(m_opt!=5);
    	f.close();
    	system("PAUSE");
    	return 0;
    }
    Se apro il file in modalità ios:ut invece che ios::ate la seconda volta, quando vado a leggere i dati su file non mi compare nulla su schermo. Penso che i dati non vengano scritti.

  9. #9
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Hai fatto un bel minestrone.
    In linea generale il main dovrebbe limitarsi solo a chiedere cosa si vuole fare; altre cose non sono di sua pertinenza.
    Il file che apri nel main viene chiuso solo quando il programma esce, quindi c'è rischio serio di corruzione dati. Inoltre "inizializzi" (?) il file con 100 strutture vuote (e che serve?) e c'è la funzione record_vuoto() il cui scopo è dubbio.

    Il tuo main dovrebbe limitarsi a chiedere: che vuoi fare? E chiamare la funzione corrispondente.
    Sarà la funzione a prendersi carico di gestire il file interno. Similmente le altre funzioni faranno quello che devono fare, ma sapendo di poter elaborare un file consistente e non corrotto di dati.
    Il main dovrà essere qualcosa del genere: (nota che ho tolto le system() che non digerisco e la string la uso per comodità).
    codice:
    int main(int argc, char* argv[] ) {
    	cout << "Programma di test ferramenta\n\n\n";
    	string myFile = "hardware.dat";
    	int m_opt;
    	do{
    		cout << "\n\n\nScegli un'opzione:\n1)Inserisci attrezzo nel file.\n2)Elenca attrezzi." <<
    				"\n3)Elimina attrezzo non presente in magazzino.\n4)Aggiorna dati attrezzo.\n5)Esci." <<
    				"\nInserisci opzione: ";
    		cin >> m_opt;
    		cin.sync();
    		switch(m_opt){
    		case 1:{
    			inserisci_attrezzo(myFile);
    			break;
    		}
    		case 2:{
    			leggi_attrezzi(myFile);
    			break;
    		}
    		case 3:{
    			elimina_attrezzo(myFile);
    			break;
    		}
    		case 4:{
    			aggiorna_attrezzo(myFile);
    			break;
    		}
    		case 5:{
    			break;
    		}
    		default:{
    			cout << "Opzione non valida!\n";
    			break;
    		}
    		}
    	}while(m_opt!=5);
    
    }
    Alle funzioni devi passare il nome del file, non lo stream. Sarà la funzione a fare quel che deve fare. Ad esempio la inserisci_attrezzo()
    codice:
    void inserisci_attrezzo(const string& file);
    
    void inserisci_attrezzo(const string& file){
            // non serve nessuna record_vuoto(). La struttura è riempita del tutto qui.
    	Record tool;
    	cout << "\nInserisci numero identificativo attrezzo: ";
    	cin >> tool.n_id;
    	cout << "Inserisci nome: ";
    	cin.sync();
    	cin.getline(tool.nome, 30);
    	cout << "Inserisci quantita': ";
    	cin >> tool.qnt;
    	cout << "Inserisci costo: ";
    	cin >> tool.costo;
    	cout << "Inserisci note: ";
    	cin.sync();
    	cin.getline(tool.note, 80);
            // Creando il file in append, se non esiste viene creato, altrimenti il record è messo alla fine
    	ofstream f(file.c_str(), ios::out | ios::app | ios::binary);
    	if (!f) {
    		cout << "errore nella creazione del file" << endl;
    		return;
    	}
            // si scrive il record.
    	f.write(reinterpret_cast<const char*>(&tool), sizeof(Record));
            // opzionalmente si può mettere f.close(). Il file comunque è chiuso quando la funzione esce.
           // f.close();
    }
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  10. #10
    Ciao, riprendo questa discussione perchè ho risolto il problema (però non penso sia la soluzione migliore).
    In pratica, quando utilizzavo la funzione inserisci_attrezzo() aprivo l'oggetto ofstream con la modalità ios:ut | ios::ate , ma questa modalità cancella l'intero file!
    Ho avuto la conferma su questa discussione (che però non risolve il problema)

    codice:
    void inserisci_attrezzo(char* name1){
    	Record tool;
    	cout << "\nInserisci numero identificativo attrezzo: ";
    	cin >> tool.n_id;
    	cout << "Inserisci nome (usa il carattere di linea per lo spazio): ";
    	cin >> tool.nome;
    	cout << "Inserisci quantita': ";
    	cin >> tool.qnt;
    	cout << "Inserisci costo: ";
    	cin >> tool.costo;
    	cout << "Inserisci note: ";
            getline(cin, tool.note); 
    	ofstream f(name1, ios::out | ios::ate);
    	if(!f){
    		cout << "\nIl file non e' stato aperto!\n";
    		return;
    	}
    	f.seekp((tool.n_id-1)*sizeof(Record));
    	f.write(reinterpret_cast<const char*>(&tool), sizeof(Record));
    	f.close();
    }
    Ho risolto istanziando un oggetto fstream aperto in modalità standard, in modo che posso inserire dati all'interno del file senza che vengano distrutti quelli già esistenti:

    codice:
    void inserisci_attrezzo(char* name1){
    	Record tool;
    	cout << "\nInserisci numero identificativo attrezzo: ";
    	cin >> tool.n_id;
    	cout << "Inserisci nome (usa il carattere di linea per lo spazio): ";
    	cin >> tool.nome;
    	cout << "Inserisci quantita': ";
    	cin >> tool.qnt;
    	cout << "Inserisci costo: ";
    	cin >> tool.costo;
    	cout << "Inserisci note: ";
            getline(cin, tool.note); 
    	fstream f(name1);
    	if(!f){
    		cout << "\nIl file non e' stato aperto!\n";
    		return;
    	}
    	f.seekp((tool.n_id-1)*sizeof(Record));
    	f.write(reinterpret_cast<const char*>(&tool), sizeof(Record));
    	f.close();
    }
    Se apro il file con ios::app, i dati non vengono cancellati ma posso inserire i dati solo alla fine e non all'interno.


    Secondo voi è la soluzione migliore? Conoscete una modalità di apertura in output che mi permette di inserire i dati all'interno del file senza cancellare i dati già presenti?

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.