PDA

View Full Version : [c++] scrivere file binari


anyanka
18-11-2008, 16:08
Salve ragazzi, ho un problema con la scrittura dei file binari:

devo scrivere in un file delle coppie di valori stringa-double, utilizzo gli fstream, pensavo fosse sufficiente aprire il file in modalità binaria ma in realtà scrive tutto come se fosse un normale file di testo!

devo usare le istruzioni del C ??
questo è quello che ho provato a scrivere:

string out = output_s + ".bin" ;
output.open(out.c_str(), ios::binary) ; // questo è il file codificato
assert(output) ;
freq_it = min_interval_map.begin();

/** SCRITTURA DELL'HEADER **/

while(freq_it != min_interval_map.end()) {
name = (*freq_it).first ;
// output.write(name.c_str(), name.length()) ;
output << name ;
output << (*freq_it).second ;
freq_it++ ;
}

cionci
18-11-2008, 19:13
Devi usare la funzione write. Sinceramente io lo trovo scomodo, anche perché bisogna fare il cast a char *, il vecchio void * era veramente più comodo.

ofstream f("prova.dat", ios::binary);
int i = 3432;
f.write((char *)&i, sizeof(i));
i = 34213;
f.write((char *)&i, sizeof(i));
i = 34213;
f.write((char *)&i, sizeof(i));
f.close();

Volendo

anyanka
18-11-2008, 19:58
grazie per il chiarimento.. ma com'è possibile che il file che viene fuori è più grande di quello ottenuto con l'operatore << ? :confused: :mc:
inoltre per le stringhe, come dimensione devo passare sizeof(char)*num_di_caratteri?

cionci
19-11-2008, 01:48
grazie per il chiarimento.. ma com'è possibile che il file che viene fuori è più grande di quello ottenuto con l'operatore << ? :confused: :mc:
Dipende dal numero che scrivi sul file...ad esempio il numero 56 occupa 2 byte con <<, scritto in binario ne occupa 4 ;)
inoltre per le stringhe, come dimensione devo passare sizeof(char)*num_di_caratteri?
Per le stringhe, se la grandezza del campo non predefinita, dovresti scrivere prima un intero contenente il numero di caratteri che compongono la stringa (al momento dell'allocazione devi aggiungere un +1 per il carattere di fine strina) seguito dai caratteri con appunto sizeof(char)*num_di_caratteri.
Se invece la grandezza è predefinita scrivi direttamente tutto il buffer, ad esempio:

struct a
{
char stringa[20];
int x;
int y;
};

Con questa puoi scrivere direttamente la struttura con il sizeof della struttura.


struct a
{
char *stringa;
int x;
int y;
};

Con questa invece devi usare il secondo metodo e scrivere i campi uno per uno.

anyanka
19-11-2008, 14:09
Per le stringhe, se la grandezza del campo non predefinita, dovresti scrivere prima un intero contenente il numero di caratteri che compongono la stringa (al momento dell'allocazione devi aggiungere un +1 per il carattere di fine strina) seguito dai caratteri con appunto sizeof(char)*num_di_caratteri.
Se invece la grandezza è predefinita scrivi direttamente tutto il buffer, ad esempio:

struct a
{
char stringa[20];
int x;
int y;
};

Con questa puoi scrivere direttamente la struttura con il sizeof della struttura.


struct a
{
char *stringa;
int x;
int y;
};

Con questa invece devi usare il secondo metodo e scrivere i campi uno per uno.

Quello che ho segnato serve per poter poi leggere il file e recuperare correttamente la stringa o serve comunque indicare prima da quanti caratteri è composta?

cionci
19-11-2008, 16:24
Quello che ho segnato serve per poter poi leggere il file e recuperare correttamente la stringa o serve comunque indicare prima da quanti caratteri è composta?
Serve per poterla recuperare correttamente quando non ne conosci a priori la dimensione.

anyanka
19-11-2008, 16:38
ok, perfetto :)
grazie mille!

anyanka
24-11-2008, 15:43
sono riuscita a memorizzare il numero di caratteri di cui è composta ogni stringa e a recuperarla correttamente... solo che ora non riesco a recuperare il valore double che ho scritto:

questo è il codice che crea il file binario:

while(freq_it != min_interval_map.end()) {
name = (*freq_it).first ;
lun = name.length() ;
cout << "lun= " << lun << endl;
output.write((char *)&lun, 1); // att: dimensione di lun = 1 byte
output.write(name.c_str(), (sizeof(char)*lun)) ;
valore = (*freq_it).second ;
output.write((char *)&valore, sizeof(valore));
// output << name ;
// output << (*freq_it).second ;
freq_it++ ;
}

mentre questo è quello per recuperare i valori:

int i = 0, j = 0 ;
int lunghezza_tag ;
char * size ;
char num_car ;
char * valori ;
double valore ;
// char * endptr ; // serve per la funzione strtod
char * buffer = new char[lunghezza+1] ;
file_compresso.read(buffer, lunghezza) ;
// cout.write(buffer, lunghezza); // fa fare un bip
cout << endl;
cout << "\ncaratteri letti " << file_compresso.gcount() << endl;
while(i < lunghezza) {
/* leggi il primo carattere che dice quanto è lunga la stringa
* poi un num di caratteri pari alla lunghezza della stringa
* poi ancora 8 caratteri per il double
*/
num_car = buffer[j] ;
j++ ; // aggiorno la posizione nel buffer
lunghezza_tag = (int)num_car ;
cout << "num_car = " << lunghezza_tag << endl;

// leggo il tag
size = new char[lunghezza_tag] ;
for(int k = 0; k < lunghezza_tag; k++) {
size[k] = buffer[j] ;
j++ ;
cout << size[k] ;
}
cout << endl;
// leggo il valore del tag
cout << "j = " << j << endl;
// valori = new char[sizeof(double)] ; // equivalente new char[8];
valori = new char[8] ;

for(unsigned int k = 0; k< 8; k++) {
valori[k] = buffer[j] ;
cout << valori[k] ;
j++ ;
}
cout << endl;
valore = strtod(valori,NULL) ;
cout << valore << endl;
// cout.write(valori, 8) ;
// valore = atof(valori) ;
// cout.precision(8) ;
cout << valori << endl;
// j += 8 ;
i = j ;
}

cionci
24-11-2008, 15:55
Per la lettura devi usare la read e ti devi comportare in modo simmetrico alla scrittura ;) Ad ogni write deve corrispondere una read.

anyanka
24-11-2008, 16:02
quindi dovrei necessariamente leggere il file un po' alla volta.. non, come ho fatto, leggerlo tutto e poi estrapolare i valori dal buffer?
che pelotas...

edit: credo che il problema sia "solamente" nel convertire l'array di char che contiene gli 8 caratteri del valore in double!
nè atof(char *) nè strtod(char *, NULL) danno risultati...

cionci
24-11-2008, 17:14
Ma non la devi fare quella conversione, devi leggere direttamente sizof(double) byte ed li vai a mettere in un double con read ;)

anyanka
24-11-2008, 17:31
uttio...era una cretinata.. sono commossa! :cry:
grazie ancora! :D