Just nu i M3-nätverket
Jump to content

Skapa ett fil format...?


Jonas Innala

Recommended Posts

Jonas Innala

Jag vill göra ett program som gör en fil...

Men jag vill ha filen så ihop packad som möjligt så nu undrar jag hur ska jag kunna göra filen ihop packad inte zippad eller för den delen ett annat existerande pack format jag vill föra det själv finns det några generella tips någon kan ge??...

 

Har någon gjort typ ett eget fil format jag vill veta hur och om det är typ att bara att man spara i en textfil???

 

Link to comment
Share on other sites

Jonas Innala

Okej nu har jag läst om Huffman Codes Men nu återstår en fråga och det är hur skriver man Binärt i en fil?

 

Link to comment
Share on other sites

jerker olofsson

För att skriva binärt kan du använda fread() och fwrite() funktionerna om du använder FILE*, fopen osv.

 

// Skriv till en fil
size_t  fwrite ( const void * buffer, size_t size, size_t count, FILE * stream ); 

// Läs från en fil
int  fread (void * buffer, size_t size, size_t count, FILE * stream); 

// Öppna en fil, returnerar NULL om det inte går vägen
FILE * fopen (const char * filename, const char * mode); 

 

När du öppnar filen ska du öppna den som

fopen( "fil.bin", "w" );

 

och med "r" istället för "w" om du vill läsa. Alltså inte lägga till "rt" som för att läsa textfiler. På många operativsystem är det ingen skillnad om du vill öppna som text eller binärt, utan det är samma sak. Windows däremot omvandlar \n till \r\n när du skriver text och tvärtom när du läser. Så där måste du vara noga med hur du gör.

 

För att sedan skriva gör du bara något liknande:

// C exempel
#include <stdio.h>

char buffer[5];
buffer[0] = 0;
buffer[1] = 1;
buffer[2] = 2;
buffer[3] = 3;
buffer[4] = 4;

FILE* f = fopen( "test.bin", "w" );
if( f )
{
// 5 är antalet element du vill skriva, och 1
// storleken på varje element (char = 1 byte).
// Du skulle också kunna skriva:
// fwrite( buffer, sizeof( buffer[0] ), sizeof( buffer ), f );
// Så fungerar din write vilken storlek du än har på
// din array, men vanligtvis brukar man inte skriva
// "fixed size" arrays.
fwrite( buffer, 1, 5, f );

// För att bara skriva en integer gör du:
int fun = 10;
fwrite( &fun, , sizeof( int ), f );
}

 

Dessa exempel var i gammal C-syntax som C++ ärvt. Eftersom du inte specar vilket språk du programmerar i får du även som bonus ett exempel för C++..

 

// C++ exempel
#include <fstream>

std::fstream f;
f.open( "file.bin", std::ios::binary|std::ios::out );

if( f.is_open() )
{
char buffer[5];
buffer[0] = 0;
buffer[1] = 1;
buffer[2] = 2;
buffer[3] = 3;
buffer[4] = 4;

// Skriv 5 bytes från buffer
f.write( buffer, 5 );

// Skriv en integer och en float
int foo = 10;
float bar = 20;
f << foo;
f << bar;
}

 

För att sedan läsa gör du bara omvänt:

// C++ exempel
#include <fstream>

std::fstream f;
f.open( "file.bin", std::ios::binary|std::ios::in );

if( f.is_open() )
{
char buffer[5];

// Läs 5 bytes från buffer
f.read( buffer, 5 );

// Läs en integer och en float
int foo = 0;
float bar = 0;
f >> foo;
f >> bar;
}

 

För mer info kan du kika på:

http://www.cplusplus.com/ref/cstdio/index.html

för den gamla C syntaxen...

 

..och på:

http://www.cplusplus.com/ref/iostream/fstream/

för C++ file streams.

 

 

Link to comment
Share on other sites

jerker olofsson

Jo.. du måste veta ordningen du ska läsa.. Det behöver ju inte vara nummer. Du kan ju läsa och skriva strängar om du vill..

 

Filformat är knepiga och det finns x antal olika sätt att lösa saker på :)

 

Du kan börja med att skriva en "header" som talar om version, det brukar vara standard. Sen kan du t ex skriva ett ID och en längd. ID som beskriver vilken typ av data som en del av filen innehåller, sen en längd så att du kan hoppa över delen om du inte känner till ID:t.

 

Typ:

[Version, 4 bytes] [iD 4bytes][Length 4bytes][Data Length bytes..] [iD 4bytes][Length 4bytes][Data Length bytes..] .... [iD 4bytes][Length 4bytes][Data Length bytes..]

 

Osv :)

 

Brukar fungera ganska bra.

Om du vill hitta något speciellt ID, så behöver du inte "parsa" hela filen, utan du kan hoppa dig fram.

 

 

Link to comment
Share on other sites

Jonas Innala

Okej jag förstår och jag tror jag har kommit på en lösning som passar mitt kommande filformat....

Men jag tycker att:

 

f.read( buffer, 5 );

 

är ett ganska klumpigt sätt att ändra sättet att ändra hur många bytes den ska läsa i taget. Om man vill att den ska vara bra ihop packad så ska den ju ta upp så lite bytes som möjligt.

Finns det inget enklare och mindre klumpigare sätt att ändra hur många bytes den ska läsa?

Annars går det ju bra att ändra med f.read( buffer, 5 ); men det blir ju en hel del...

 

Link to comment
Share on other sites

jerker olofsson

Jo visst har du rätt i det.

Det var bara ett exempel...

Du får ju skriva det antal bytes du behöver..

 

class test {
void test::Save( fstream& f )
{
 f << Member1_;
 f << Member2_;
 f << Member3_;
 f << Member4_;
}

void test::Load( fstream& f )
{
 f >> Member1_;
 f >> Member2_;
 f >> Member3_;
 f >> Member4_;
}
};

class test2 {
void test2::Save( fstream& f )
{
 f << State1_;
 f << State2_;
}

void test2::Load( fstream& f )
{
 f >> State1_;
 f >> State2_;
}
};

int main()
{
 test t1,t2;
 test2 t3,t4;

 fstream record;
 record.open( "record.dat", ios::in|ios::binary );
 t1.Load( f );
 t2.Load( f );
 t3.Load( f );
 t4.Load( f );

 // Gör de saker applikationen gör.
 // .....
 // .....

 fstream record2;
 record2.open( "record.dat", ios::out|ios::binary );
 t1.Save( f );
 t2.Save( f );
 t3.Save( f );
 t4.Save( f );

}

 

Ännu snyggare kan du lösa det genom att templata alla variabler som skall sparas, och automatisera det.. Lite mer avancerat, men något sådant här kan du göra:

 

class Loadable {

protected:

std::list<LoadableVariable*> List_;

void add( LoadableVariable* lv )
{
List_.push_back( lv );
}

public:

template <class T> friend class LoadableVariable<T>;

template <class T>
class LoadableVariable
{
private:
LoadableVariable( Loadable& L ) : L_( L ) 
{
  L_.add( this );
}

Loadable& L_;
T Content_;

public:
operator T() { return Content_; }
operator = ( const T t ) { Content_ = t; }
operator < ( const T t ) { return Content_ < t; }
// osv.. alla operatorer..
};

public:
void Save( fstream& f )
{
for( std::list<LoadableVariable*>::iterator it=List_.begin(); it != List.end(); ++it )
{
f << (*it);
}
}

void Load( fstream& f )
{
for( std::list<LoadableVariable*>::iterator it=List_.begin(); it != List.end(); ++it )
{
f >> (*it);
}
}
};

 

Sen kan du använda det så här:

 


class MyClass : public Loadable {
 Loadable::LoadableVariable<int> Member1_;
 Loadable::LoadableVariable<float> Member2_;
 Loadable::LoadableVariable<std::string> Member3_;
};

class MyClass2 : public Loadable {
 Loadable::LoadableVariable<double> Ett_;
 Loadable::LoadableVariable<int> Tva_;
 Loadable::LoadableVariable<std::string> Namn_;
};

int main()
{
 MyClass m1;
 MyClass2 m2;

 m1.Load();
 m2.Load();

 // Main app..

 m1.Save();
 m2.Save();
}

 

Skrivet helt från huvet och bara menat som inspiration, det första exemplet är en bra början och jag hoppas att det inte är några problem att förstå det.

 

 

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.



×
×
  • Create New...