Gå til innhold

Binær skriving/lesing av fil?


Anbefalte innlegg

Jeg har følgende kode som funker:

 

...

std::string str = "Hello World!";
int strSize = str.size();


//
// Write file
//
std::ofstream out;
out.open(filename.c_str(), std::ios::binary);

out.write( (char *)(&strSize), sizeof(strSize) );

for(int i = 0; i < strSize, i++ )
{
out.write( (char *)(&str[i]), 1);
}

out.close();

...

 

Åpner jeg fila jeg skriver til får jeg noen merkelige tegn og "Hello World!". Komplette teksten er som følgende: "^L^@^@^@Hello World!".

 

Hva er den første biten før "Hello World!"? den har jo sammenheng med:

 

out.write( (char *)(&strSize), sizeof(strSize) );

Endret av South_Bridge
Lenke til kommentar
Videoannonse
Annonse

Takk for svar. Var det jeg var ute etter.

 

videre: hva om jeg ønsker å lagre et selvspikka objekt? feks

 

struct Person
{
std::string name;
int age;

Person(std::string n, int a)
{
 name = n;
 age = a;
}
}

 

Binært til en fil og så lese det igjen?

 

Har skrevet funksjonene

 

WriteBinaryTofile(std::fstream &file, Person &p)
{
file.seekp( 0, std::ios::end);
file.write( (char *)&p, sizeof(p) );
}

Person ReadBinaryFromFile(std::fstream &file)
{
file.seekg(0, std::ios:beg);
Person p;
file.read( (char *)&p, sizeof(p) );

return p;
}

 

Men jeg får bare "Segmentation fault" fra kompileren.

Lenke til kommentar

Okey... noe slikt da:

 

FILE* pFile;
pFile.fopen( filename.c_str(), "w");

Person p;
p.name = "ole";
p.age = 30;

pFile << p;

fclose(pFile);

 

Jeg får da følgende errors:

 

main.cpp:57: error: request for member 'fopen' in 'pFile', which is of non-class type 'FILE*'

main.cpp:63: error: no match for 'operator' in 'pFile << p'

main.cpp:26: note: candidates are: std::ostream& operator<<(std::ostream&, Person&)

Lenke til kommentar

videre: hva om jeg ønsker å lagre et selvspikka objekt? feks

 

Da er svaret "det kommer an på hva du ønsker å oppnå". Aller først -- "Standard C++ IO streams and locales" av Langer og Kreft er det du ønsker å ta en titt på.

 

I utgangspunktet er det slik at enhver datatype må kunne representeres som en strøm av bytes på en slik måte at det å lese denne representasjonen tilbake gir mening. Legg merke til at "gi mening" kan bety veldig mye rart, alt ettersom hva som er målet med oppgaven.

 

Det GeirGrusom foreslår er tilpasningen av dine egne objekter til "formattert I/O". Hvis du virkelig ønsker dette, så er det å skrive din egen operator<<() og operator>>() veien å gå. Du må da tenke litt på hvordan operator<<() og operator>>() virker sammen med de enkelte datatypene som disse operatorne er allerede definert for.

 

Dersom målet er å lagre en datastruktur for så å kunne lese den tilbake inn i minne, så er ikke formattert IO den beste tilnærmingen. Det vil være mer hensiktsmessig å lage et format som er tilpasset til applikasjonens behov. Wikipedia har garantert veldig mye fint om "serialization" og "marshalling", som er nøkkelord i dette tilfellet. Det du ønsker da er å lage en passende metode i din egen type som skriver "seg selv" ut til den underliggende filen. Da må du ta stilling til slike ting som byte-order, representasjon for basaltypene, hvordan postene innad et objekt blir skilt fra hverandre, hva du skal gjøre med sirkulære datastrukturer, hvordan du skal representere pekere, osv.

 

Så, hva ønsker du egentlig å oppnå?

 

WriteBinaryTofile(std::fstream &file, Person &p)
{
file.seekp( 0, std::ios::end);
file.write( (char *)&p, sizeof(p) );
}

 

Det er *svært* sjelden at det å skrive ut den underliggende byterepresentasjonen til objektet til fil vil gjøre det du vil. Hva om implementasjonen din har masse statusinformasjon i objektet? Hva som GC bruker denne til noe? Eller tracing/profiling-biblioteket? Hva om p inneholder pekere (hvilket en std::string vil høyst sannsynligvis gjøre)? (det å skrive ut en minneadresse (== peker) til en fil innebærer slettes ikke at den adressen lest tilbake vil gi mening).

 

(I tillegg er jeg faktisk usikker på om det å aksessere en Person* gjennom en char* er lovlig. Konverteringen er garantert til å virke. Dvs Person* -> char* -> Person* er lovlig. Men om *(char*) på en Person* er lovlig er jeg litt mindre sikker på).

 

Men jeg får bare "Segmentation fault" fra kompileren.

 

Ja, av grunner nevnt over.

 

Så, hva er det du egentlig vil?

Lenke til kommentar

Takk for resonsen zotbar1234, du også GeirGrusom.

 

Det jeg vil, og det jeg tenkte å lære meg er å dytte flere ting inn i en fil.

 

Ta world of warcraft som et eksempel. På overflaten har de feks dytta all musikk (av ukjent format) ned i .mpqfiler. .mpq filene er da arkiv/kontainere for media filene.

 

Jeg hadde lyst til å prøve noe av det samme da jeg har et par baller i lufta... hvordan kan jeg feks lage en fil som inneholder flere wavs og/eller kanskje ikke annen media? Jeg tenkte ikke så avansert som blizz har gjort det, men det er en teknikk jeg har hatt lyst til å lære.

Lenke til kommentar

aha et virituelt fil system.

Vel det enkleste er bare å legge en array (samt hvor lang arrayen er) av noe alal dette i starten av filen.

struct VFSFileEntry
{
 char Name[200]; //Brukes til oppslag
 int  FilePos;//Posisjonen til filen i vfs filen.
}

 

Så er det bare å dumpe filene inn i filen og notere seg hvor de starter og slutter.

Lenke til kommentar

Jeg hadde lyst til å prøve noe av det samme da jeg har et par baller i lufta... hvordan kan jeg feks lage en fil som inneholder flere wavs og/eller kanskje ikke annen media?

 

Enten bruke et passende container-format som finnes alt, eller definere ditt eget, og skrive wav-dataene på det formatet. Valget vil antageligvis styres av hva du har tenkt å gjøre med disse wav-filene videre (kan f.eks. tenkes at lydbiblioteket som du bruker for å spille av wav har noen føringer/måter å gjøre det på).

Lenke til kommentar

edit: opptill flere kom meg i forkjøpet...

 

Ok, ikke noen stor sak egentlig.

 

Det er hovedsaklig to måter å gjøre det på:

Du kan separere data fra filstrukturen(Filsystemer som FAT og andre), eller du kan gjøre begge deler i samme struktur (Total Annihilation .TNT filer, .3ds for 3d studio 3.0)

 

Den første kan være litt krunglete, fordi du må bruke filpekere, og det er litt vanskelig å definere filpekere riktig før datene blir skrevet. Men den første har en klar fordel over at all data ikke trengs å traverseres for å danne en struktur fra fila, dog dette er ikke så viktig dersom du bruker memory mapped IO.

 

Men ihvertfall: dann datastrukturer du tror er nyttig (for eksempel header for hver fil, for directory osv.)

Lese/skrive til filen er ikke vanskelig. Som sagt bruker jeg fread/fwrite fordi jeg synes diss er litt enklere å bruke.

Endret av GeirGrusom
Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...