Binärdateien - funktionsweise

  • GM 8

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Binärdateien - funktionsweise

    Hallo Leute!
    Ich habe mich noch nie mit binärdateien beschäftigt und habe deshalb 0 Ahnung wie sie genau funktionieren.

    Ich habe einen Speicher und ladescript für Maps geschreiben der mir in einem Textfile speichert welcher Block (= Block ID) an welcher Position existiert. (Wie bei Minecraft)
    Dieser eine Block ist in einer zeile gespeichert.
    Auf diese Art udn weise kann ich in jeder zeile (mithilfe von Trennzeichen) die einzelnen Werte identifizieren.

    Jedoch würde ich dies gerne mit Binärfunktionen lösen (da sie angeblich bessere Funktionen zur Handhabung von daten haben.)
    So ist es mir wichtig dass ich eine Zeile (also einen gespeicherten Block) in der Datei "überschreiben" kann ohne die ganze Datei auszulesen und mit der änderung komplett neu zu speichern. (Das wäre ziemlich ressourcelastig.) Bei binärdateien soll das jedoch möglich sein.

    Die Frage ist nur WIE funktionieren die binärdateien? Wie genau werden die Werte dort verwaltet? Wie kann ich beim Laden zwischen den x,y Koordinaten und der eigentlichen Block-ID unterscheiden?
    Wäre nett wenn mir das irgendjemand erklären könnte. ^^ (Peinlich dass ich als GML fortgeschrittener noch nie damit gearbeitet habe. XD)
  • Im Groben gesagt, stehen nur Bytes drin, also kein lesbarer Text, Werte von 0-255. Du müsstest dir eben irgendein spezielles System zulegen.
    Beispielsweise kannst du 0-Bytes als Trennzeichen verwenden. Zu deinem System käme mir die Idee, im ersten Byte die Länge der Blockid zu Speichern, in den nachfolgenden Bytes die Blockid, und danach eben die Koordinaten, alles getrennt durch ein 0 Byte. Wenn du es dir einfach machen willst, kannst du einfach ord("Zahl") verwenden, um Zahlen zu konvertieren, denke aber daran, dass du es Ziffer für Ziffer tun musst.
    Im Endeffekt wirst du aber nicht viel herausholen, da die Binärfunktionen des GM's auch sehr langsam sind.

    © 2008 by Teamgrill Productions
  • Die Frage ist nur WIE funktionieren die binärdateien? Wie genau werden die Werte dort verwaltet? Wie kann ich beim Laden zwischen den x,y Koordinaten und der eigentlichen Block-ID unterscheiden?
    So WIE Textdatein. Wenn in einer Textdatei hello <enter> world! steht, steht in der Datei die ASCII Codes der Zeichen (Zeilenumbruch ist 10 und 13 bei Windows!). Kannste dir ja mal mit einem Hex-Editor ansehen ;). Du kannst selbst entscheiden wie deine Binär Datei später aussehen soll (du kannst nur Bytes nach ein andere einlesen, also so wie bei Text Buchstabe Weise). Schau dir doch mal das BMP Format an (zu finden bei Wikipedia).

    Deine Datei könnte so aussehen: <Magische Zahl die du selbst wählen kannst> <header> <data>
    Die Magische Zahl ist das was die Datei ganz genau beschreibt (so das das Programm später weiß das es einer von deinen Maps ist) bei BMP Datei ist das z.B. BM.
    Der Header beschreibt z.B. wie groß die Map ist, wie sie heißt, Spawn Punkt vom Spieler, Inventar etc.
    "Data" beschreibt die Blöcke du könntest z.B. das so aussehen lassen <x Position vom Block><y><Block-ID>
    Der Game Maker kann zwar nur Bytes einlesen (0-255), aber mit ein paar Tricks gehen auch Shorts(0- öhm 2 hoch 16 minus 1) die zwei Bytes groß sind und Ints (0-2 hoch 32 minus 1) die vier Bytes groß sind. Für die größe der Map beim Header und bei der x/y kannste z.B. ints verwenden und bei der Blockid nen Byte.

    Du kannst das ganze noch verfeinen für die Ebenen und sagen bei der Data ab x=0 y=0 blockid=255 beginnt eine neue Ebene oder fügst noch bei den Block noch ein Extra teil ein das dann noch die Ebene beschreibt.

    Das ganze klingt nun ein bisschen kompliziert ist es aber nicht. Probier einfach mal rum, und schaue dir andere Datei Formate an(Doku+Hex-Editor).
    Du könntest stats Shorts und Ints auch das da benutzten:

    GML-Quellcode

    1. //Lesen
    2. var bla,bla2;
    3. bla=0;
    4. bla2=file_bin_read_byte(filehandle);
    5. while(bla2==255) { bla+=255; bla2=file_bin_read_byte(filehandle); }
    6. bla+=bla2;
    7. //Schreiben
    8. var bla;
    9. bla=555;
    10. while(bla>=255) { file_bin_write_byte(255); bla-=255; }
    11. file_bin_write_byte(bla);
    Alles anzeigen
    wupto.net/ Nicht meine Seite!
    We love Koalas.

    GM-D-Spam-o-Meter: 32%
  • Ich arbeite grade an einem programm mit dem ich unteranderem dateien in schematics (genutzt für MCedit [minecraft]) exportiere.
    Da die source für den exportierer von einer dritten person stammt möchte ich sie nicht verbreiten, doch ich kann dir einzelne scripts per pm schicken wenn du möchtest

    das problem ist das die größe immer ein limit hat, und wegen preformance würde ich es dir sowieso raten: unterteil die map am besten in chunks

    Hellfish
  • unterteil die map am besten in chunks


    Das tuhe ich schon längst. ;)
    Das Problem mit dem ich zu kämpfen habe ist die Performance der sicherung und des ladens von bestehenden Chunks.
    Ich habe wirklich keine Ahnung wie Notch es hinbekommen hat in echtzeit einen Chunk zu speichern und den anderen zu generieren bzw zu laden (je nach bedarf.) Soviel ich weiss nutzt Minecraft ja kein Multithreading.

    Ich wollte eben versuchen während des Spiels die einzelnen änderungen (z.B: einen Block zu platzieren) gleich in eine Datei zu schreiben um am ende nicht den ganzen Chunk auf einmal zu sichern.
    Das Problem ist nur dass ich nicht ohne weiteres eine Zeile eines Textfiles einfach so mit neuen Werten überschreiben kann.
    Darum die Binary funktionen.

    @ Topic:

    Das Problem ist dass ich mir das nur schwer vorstellen kann. In der Hilfe habe ich mir die Binary funktionen schon durchgelesen.
    Das Problem ist dass ic hsie nicht wirklich verstehe. z.B: was ist mit dem "zeiger" bei der "seek" funktion gemeint?
    Was die ID sein soll weiss ich ebenso nicht.

    Bei einem Textfile ist das für mich ja noch übersichtlich und lesbar gestaltet, aber bei Binary funktionen kann ich mir sowas nur schwer vorstellen.
    Wenn ich die Zahl "0" als trennzeichen nutze bekomme ich aber ein Problem da bei mir auch Koordinaten mit der Position 0 gespeichert werden. Dadurch entstehen ungewollte Treinnzeichen die mir das System vermiesen würden.

    Also nehme mal an eine Binary datei würde so ausschauen:

    GML-Quellcode

    1. 025521233


    Wie genau kann ich nun darauf schliessen wo welcher Wert platziert wurde und wieviel Stellen er hat? (also ob er 2 oder 3stellig ist)
    Oder schaut solch eine Binary datei ganz anders aus? (Werde mir dann nen Hex-Editor runterladen.)

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von LEWA ()

  • Gut, dass ich nicht schlafen kann. :D
    Zur Seek-Funktion:

    file_bin_seek(fileid,pos) Moves the current position of the file to the indicated position. To append to a file move the position to the size of the file before writing.


    fileid ist natürlich die Datei, pos der Offset in Bytes vom Beginn der Datei.
    Zu deinem anderen Problem: Vergiss das mit den Trennzeichen, das ist Unsinn.
    Du solltest dir mal eine Struktur für dein Dateiformat überlegen, wie es Henrik bereits erwähnt hat. Dies könnte ungefähr so aussehen:

    Quellcode

    1. <MAGIC STRING> // Z.b. 4 bytes, muss immer "L" "E" "W" "A" sein, damit kannst du feststellen ob die Datei gültig ist
    2. <METADATA> // Hier kannst du besondere Informationen über die Map reinstellen, zum Beispiel die Größe
    3. <DATA CHUNK 1> // Könnten zum Beispiel zwei Shorts sein für die X- und Y- Koordinaten und ein Byte für die Art des Feldes (z.B. Frei, Blockiert, Leiter)
    4. <DATA CHUNK 2>
    5. <DATA CHUNK ..>
    6. <DATA CHUNK n>


    Beim Auslesen gehst du wie folgt vor:
    Du überprüfst erst einmal, ob der Magicstring gültig ist, wenn er falsch ist oder nur Müll enthält, weißt du, dass die Datei ungültig ist. Dann liest du die Metadata aus und schließlich die einzelnen Chunks. Das wichtigste ist jedoch, dass du weißt wie man große Zahlen oder auch Gleitkommazahlen in Bytes darstellen und wieder zusammenfügen kann.
    Sagen wir mal du willst im <METADATA>-Teil die Breite und Höhe deiner Map speichern. Mit 1 Byte kannst du nur 0 - 255 speichern, was wahrscheinlich zu wenig sein wird, wenn du hingegen 2 Bytes pro Abmessung verwendest kannst du Zahlen von 0 - (2^16 ) - 1 darstellen, was reichen sollte. D.h. du hast 4 Bytes als Metadata, je 2 Bytes sind die Breite und die Höhe.

    Ach ich werde langsam müde, aber ich sag dir noch, wie man mehrere Bytes wieder zusammenfügen kann. Also sagen wir du hast die zwei Bytes für die Breite ausgelesen und willst den richtigen Wert wieder berechnen:

    GML-Quellcode

    1. var value;
    2. value = lsb + // Lsb ist das Byte mit der geringeren Wertigkeit
    3. msb << 8; // Msb ist das Byte mit der höheren Wertigkeit und muss daher um 8 Bits (= Byte) geshiftet werden


    Außerdem solltest du noch beachten, in welcher Reihenfolge du die Bytes speicherst, sprich von höchster Wertigkeit zu niedrigster oder umgekehrt...
    Gute Nacht....

    © 2008 by Teamgrill Productions
  • Ich verstehe leider nur Bahnhof. :(

    Könnte evtl jemand so ein beispiel script schreiben mit dem man mehrere Variablen speichern und auch korrekt auslesen kann?
    So könnte ich mir selbst davon ein Bild machen wie das ganze funktioniert. Die ganze theorie ist mir auf dem ersten Blick ein wenig unverständlich. XD
  • LEWA schrieb:

    Ich verstehe leider nur Bahnhof. :(

    Könnte evtl jemand so ein beispiel script schreiben mit dem man mehrere Variablen speichern und auch korrekt auslesen kann?
    So könnte ich mir selbst davon ein Bild machen wie das ganze funktioniert. Die ganze theorie ist mir auf dem ersten Blick ein wenig unverständlich. XD


    Mal schaun, ob ich dir was basteln kann. Ich persönlich würde niemals die Binärfunktionen des GMs verwenden, da das ganze sehr eingeschränkt ist. Stattdessen würde ich mir eine DLL in C++ schreiben, da es so viel einfacher wäre.

    EDIT: Dieser Artikel ist sicherlich auch interessant, da er beschreibt, wie Doubles in Bits dargestellt werden, welche auch der GM intern verwendet.

    © 2008 by Teamgrill Productions
  • Was würdest du mir in dem Falle den empfehlen?
    Für DLLs muss man sprachen wie C# udn delphi können. ICh bin jedoch nur der Sprache GML (und ein wenig JAVA) mächtig.

    Ich habe also nur die Möglichkeit auf die GM Internen Funktionen zurückzugreifen. Die Binary funktionen haben dabei mehr möglichkeiten als die von Textdateien.
    Muss damit eben irgendwie über die runden kommen. :/

    Wäre aber super wenn du mir ein leicht verständliches example programmieren würdest. ^^
  • Ich habe mir die 39DLL schon mehrmals angesehen, jedoch wusste ich bis dato nicht dass sie File-Funktionen zum auslesen und speichern von Dateien besitzt.
    Ich habe zumindest keine Dokumentation finden können die das beinhaltet hat.

    Hätte da evtl jemand irgendeine Doku für die 39DLL in denen diese file-Funktionen behandelt werden?
  • Hallo Leute. Ich weiss, dies gehört zwar nicht mehr zum Topic "Binary files" jedoch wollte ich da nicht nen extra thread aufmachen.

    Ich habe mir die 39DLL runtergeladen und mit den filescripts ein wenig herumprobiert.
    Ich sehe leider keinen Vorteil gegenüber den GM-File funktionen.
    Siek ann zwar mehr, das stimmt, aber sie bietet keine Funktion die mir irgendwie helfen könnte. z.B: kann man mit ihr auch nicht eine Zeile eines Textfiles einzeln editieren.

    Habt ihr irgendeine Ahnung wie ich dieses "Problem" mit der Datensichrerung aus dem weg gehen kann?
    Es wäre schon eine große hilfe wenn es irgendwie möglich wäre einzelne Zeilen eines Textfiles editieren zu können. :(
    (oder alles einfach mit den Binary Funktionen des GMs machen. -.-)

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von LEWA ()

  • Hi Lewa,
    ich habe dir gestern eine PM geschickt mit demproject an dem ich grade arbeite, und einer erklärung wie du es auf dein spiel anwenden kannst.
    In diesem project ist auch eine sehr nutzvolle dll enthalten, da meiner meinung nach die binäry funktionen von GM zu langsamund eingeschränkt sind.

    Hellfish
  • Vergiss die Vorstellung von Zeilen. Die Funktion filesetpos ist in diesem Fall das richtige. Sie setzt den Zeiger auf eine bestimmte Anzahl von Bytes. Du könntest zb den Zeiger immer auf das nächste <BLOCKID> springen lassen und diese dann auslesen, und falls es die richtige Position ist, die neuen Werte hineinschreiben.

    © 2008 by Teamgrill Productions