Datendatei aufsplitten, konvertieren und Einzelteilen speichern



  • Meine Datendateien sind etwa wie folgt aufgebaut.

    Zu Beginn findet man den 8-Stelligen Header der Datei, wobei an Stelle 5 die Dateiversion zu finden ist. Die Wertepaare danach sind die Adressen und Größen der unterschiedlichen Datencontainer, wobei die ersten 4 Stellen die Größe des Containers angeben und die letzten 4 Stellen den Beginn des Containers. Die Werte sind dabei in umgedrehter Reihenfolge in HEX angegeben (ich glaube das nennt man Little Endian). Du den Dateiversionen, davon gibt es 3 oder 4. Sie Unterscheiden sich praktisch nur in der Anzahl der Datenkontainer. Der Aufbau ist ansonsten weitgehend gleich (abgesehen von z.T. größeren Datensätzen in den Containern und z.T. andere Reihenfolgen der vegleichbarere Datencontainer). Hier ein Beispiel der Dateiversion 62 bzw. 3E in Hex:

    Offset(h) 00 04

    00000000 44415441 3B000000 DATA;...
    00000008 503D0000 10010000 P=......
    00000010 00004800 603E0000 ..H.>.. 00000018 10030700 603E4800 ....>H.
    00000020 C0790A00 70414F00 Ày..pAO.
    00000028 EC890000 30BB5900 ì‰..0»Y.
    00000030 00000000 1C455A00 .....EZ.
    00000038 D08F0000 1C455A00 Ð....EZ.
    00000040 808B7100 ECD45A00 €‹q.ìÔZ.
    00000048 18810C00 6C60CC00 ....lÌ. 00000050 80140000 84E1D800 €...„áØ. 00000058 80030000 04F6D800 €....öØ. 00000060 800D0000 84F9D800 €...„ùØ. 00000068 00000000 0407D900 ......Ù. 00000070 00000000 0407D900 ......Ù. 00000078 00000000 0407D900 ......Ù. 00000080 00000000 0407D900 ......Ù. 00000088 70110000 0407D900 p.....Ù. 00000090 40030000 7418D900 @...t.Ù. 00000098 60040000 B41BD900...´.Ù.
    000000A0 8A040000 1420D900 Š.... Ù.
    000000A8 DC8F0000 A024D900 Ü... $Ù.
    000000B0 549F0000 7CB4D900 TŸ..|´Ù.
    000000B8 5CDF0000 D053DA00 \ß..ÐSÚ.
    000000C0 EC4B0000 2C33DB00 ìK..,3Û.
    000000C8 809E0000 187FDB00 €ž....Û.
    000000D0 34D10600 981DDC00 4Ñ..˜.Ü.
    000000D8 74730300 CCEEE200 ts..Ìîâ.
    000000E0 70140000 4062E600 p...@bæ.
    000000E8 887D0100 B076E600 ˆ}..°væ.
    000000F0 450B0300 38F4E700 E...8ôç.
    000000F8 F8130000 80FFEA00 ø...€ÿê.
    00000100 00000000 00000000 ........
    00000108 00000000 00000000 ........

    Der erste Container startet also bei 00000110 (DEZ 272) und hat eine Länge von 00003D50 (DEZ 15696) usw.. Die meisten dieser Container enthalten Datensätze mit festgelegter Datensatzlänge, im Wesentlichen reine Zahlenlisten (Hex-Daten, z.T. IEEE754-Daten oder z.T. Kombinationen aus beiden).

    All diese Container lese ich zur Zeit als Text-Datei in Excel ein, drehe die little Endian Reihenfolge wenn nötig um und konvertiere die Zahlen mit "=HEXINDEZ(wert)" bzw. nutze das folgende Macro um die Gleitkommazahlen umzuwandeln:

    Option Explicit
    
    Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
    
    Sub HEX32_to_IEEE754r_32_le()
    
    Dim bytArray(0 To 3) As Byte
    Dim fResult As Single
    Dim byte_0 As String
    Dim byte_1 As String
    Dim byte_2 As String
    Dim byte_3 As String
    Dim s As String
    Dim letzteZeile As Long
    Dim i As Long
    
    ' Werte können Little Endian bleiben wie im Datenkontainer
    ' Beispielwerte: 0000A0C3 = -320 oder 0050C644 = 1586,5
    
    ' Zuerst die Anzahl der Werte ermitteln:
    
    letzteZeile = IIf(IsEmpty(Range("A65536")), Range("A65536").End(xlUp).Row + 1, 65536)
    
    For i = 1 To (letzteZeile - 1)
            s = Worksheets(1).Cells(i, 1).Value
            If s = "0" Then
                bytArray(3) = "&H00"
                bytArray(2) = "&H00"
                bytArray(1) = "&H00"
                bytArray(0) = "&H00"
            Else
                byte_0 = Mid(s, 1, 2)
                byte_1 = Mid(s, 3, 2)
                byte_2 = Mid(s, 5, 2)
                byte_3 = Mid(s, 7, 2)
                bytArray(3) = "&H" + byte_3
                bytArray(2) = "&H" + byte_2
                bytArray(1) = "&H" + byte_1
                bytArray(0) = "&H" + byte_0
            End If
        CopyMemory fResult, bytArray(0), 4
        Worksheets(1).Cells(i, 2).Value = fResult
    Next
    
    End Sub
    

    Ist es möglich solche Operationen in C++ "einfach" umzusetzen? Z.B. das automatische Auslesen des Inhaltsverzeichnisses und das zerteilen und Speichern der einzelnen Datenkontainer? Dateien?
    Könnt man diese Einzeldateien dann automatisch auch in Dezimalzahlen konvertieren und als CSV-Datei speichern?


  • Mod

    Kurz gesagt: Ja, das ist möglich und auch gar nicht mal so schwer. Die Frage ist aber, woran hapert es bei dir bei der Umsetzung in C++?



  • SeppJ schrieb:

    Kurz gesagt: Ja, das ist möglich und auch gar nicht mal so schwer. Die Frage ist aber, woran hapert es bei dir bei der Umsetzung in C++?

    Ja, ich kann leider kein C++. Wenn ich bisher diese Daten bearbeiten oder analysieren wollte, hab ich mir mit klassischen PC-Programmen ausgeholfen (Hex-Editor, Excel und Co.), bin aber durch die immensen Dateigrößen hiermit am Ende und suche einen neuen Weg und / oder Hilfe.


  • Mod

    Du öffnest die Datei, suchst den Header. Liest die Länge und den Anfang der Daten aus dem Header. Springst zum Anfang und liest die Daten. Wandelst die Daten in dein gewünschtes Format um (habe ehrlich gesagt nicht verstanden, was du da überhaupt machen willst). Speicherst die Daten. Fertig.

    Dazu brauchst du: Solide Kenntnisse über Kontrollstrukturen, solide Kenntnisse über das binäre Lesen von Dateien, rudimentäre Mathekenntnisse.

    MS-Office-User schrieb:

    [Wall of text]

    Und bitte: Fasse dich kurz! Niemand hat Lust dir zu helfen, wenn er sich erstmal deine Lebensgeschichte durchlesen muss. Bitte präzise Fragen stellen und den Leser nicht mit irrelevanten Informationen überschwemmen.



  • SeppJ schrieb:

    Du öffnest die Datei, suchst den Header. Liest die Länge und den Anfang der Daten aus dem Header. Springst zum Anfang und liest die Daten. Wandelst die Daten in dein gewünschtes Format um (habe ehrlich gesagt nicht verstanden, was du da überhaupt machen willst). Speicherst die Daten. Fertig.

    Klingt einfach, zumindest wenn man weiss wie es geht. 🙄

    Nicht ganz was ich haben wollte, aber ich bin schon ganz zufrieden, dass ich es zumindest geschafft habe wenigstens den Header und das Inhaltsverzeichnis zu lesen und in DEZIMAL auf dem Bildschirm auszugeben.

    /*
    	Version 01
    	Header und Inhaltsverzeichnis lesen und als Dezimalzahl ausgeben. 
    	Daten-Dateiversion 55 mit 39 Containern.
    */
    
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void) 
    {
       int Zeilen[80];
       /*
           Dateiversion 55 hat 39 Container,
           d.h. 40 Zeilen im Inhaltsverzeichnis incl. Header.
           Bei 4 Byte macht das dann 80 Zeilen die gelesen werden müssen.
    	   Bei anderen Dateiversionen die Zeilenzahl anpassen!!!
       */ 
    
       FILE *Inhaltsverzeichnis;
       /*
           Name des Datensatzes. 
       */ 
    
       int i;
    
       Inhaltsverzeichnis = fopen("test.dat", "r+b");
       /*
           Öffnen der Datei des Datensatzes. 
       */ 
       if(Inhaltsverzeichnis != NULL)
          fread(&Zeilen, sizeof(int), 80, Inhaltsverzeichnis);
          /*
    		 Festlegen der Anzahl von Zeilen die gelesen werden sollen. 
    	  */ 
    
       for(i = 0; i < 80; i++)
          printf("Wert %d in Dezimal = %d\n", i, Zeilen[i]);
          /*
             Ausgabe von 4 Byte als Dezimalzahl untereinander. 
    		 Angefangen beim Header (2 Reihen), gefolgt von Datensatzlänge
    		 und Datensatzbeginn der einzelnen Container. Die Anordnung 
    		 in Form von Paaren funktioniert bisher nicht. Vielleicht
    		 mit fseek set oder current und je einer Schleife pro Container
    		 bzw. Datenpaar???
          */ 
    
     return EXIT_SUCCESS;
    }
    

    Länge und Start nebeneinander zu bekommen habe ich leider nicht hinbekommen, auch muss ich mal gucken wie ich die Datensätze des Headers nun zum Zerteilen der Datei nutzen kann. Ist mir noch ein Rätsel.


  • Mod

    Du machst da C, kein C++, daher kann ich dir nicht weiterhelfen. Du solltest wohl besser noch mal im ANSI C Forum fragen.



  • Dieser Thread wurde von Moderator/in pumuckl aus dem Forum C++ in das Forum ANSI C verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • SeppJ schrieb:

    Du machst da C, kein C++, daher kann ich dir nicht weiterhelfen. Du solltest wohl besser noch mal im ANSI C Forum fragen.

    Ups. Das erklärt mir auch warum ich das script auf Visual Express 2008 nicht compilieren konnte sondern nur auf meinem alten Visual 6.0. Wo wäre ich denn besser aufgehoben mit der Dateizerlegung, Datenumwandlung (IEEE754 zu Dezimal und Hex zu Dezimal) sowie ggf. später eine Datenkombinierung und Ausgabe in ein definiertes Textformat. C oder C++? Vom Grundsatz bastel ich ja mehr als alles andere, da sollte ich gleich bei der richtigen Basis anfangen zu basteln.



  • MS-Office-User schrieb:

    Wo wäre ich denn besser aufgehoben [...] C oder C++?

    Python.



  • nwp2 schrieb:

    Python.

    nicht doch wenn er sich schon hier eingefunden hat;)



  • nwp2 schrieb:

    MS-Office-User schrieb:

    Wo wäre ich denn besser aufgehoben [...] C oder C++?

    Python.

    Ne, vor Schlangen hab ich Angst. :p

    Dumm ist, dass mein altes Visual 6.0 nicht auf Vista funktioniert. Musste für das peinliche Script da oben extra meinen alten XP-Rechner aus der Mottenkiste holen, da ich mit dem gestern runtergeladenen Visual Express 2008 nicht zurecht kam. Naja, im Prinzip ist mir egal womit ich das am Ende mache, hauptsache ich bekomme es hin. Ich bastel heute abend mal weiter. Vielleicht bekomme ich ja doch noch was besseres hin als totaler Noob. MS Excel ist einfacher. 😃



  • hat hier nicht mal jemand geschrieben er verwendet vc++6.0 mit vista? evtl. läufts im kompatibilitäts modus? oder braucht admin rechte oder so?



  • noobLolo schrieb:

    hat hier nicht mal jemand geschrieben er verwendet vc++6.0 mit vista? evtl. läufts im kompatibilitäts modus? oder braucht admin rechte oder so?

    Vista meckert schon bei der Installationsidee. Dort wird direkt verweigert mit Hinweis auf fehlende Kompatiblität.

    So, ich hab's geschafft mir das Inhaltsverzeichnis praktisch komplett und sortiert auf dem Bildschirm auszugeben. Vermutlich eine ziemlich beknackte Art und Weise und ich bin noch nicht so weit, dass ich die Daten auch nutzen kann, aber schon mal etwas. 😃

    Nur das Teilen der Datenlänge mit der einzelnen Datensatzlänge klappt nicht. Ich dachte so könnte ich auch angeben wieviel Datensätze im jeweiligen Container sind.

    Hier mein Script für die ersten 8 Container. 🤡

    /*
    	Version 02
    	Header und Inhaltsverzeichnis lesen und als Datenbeginn 
             und -länge sortiert als Dezimalzahl ausgeben. 
    	Daten-Dateiversion 55 mit 39 Containern.
    */
    
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void)
    {
       int Zeilen[80];
       int s; 
       int l;
    
       FILE *Inhaltsverzeichnis;
    
       Inhaltsverzeichnis = fopen("test.dat", "r+b");
    
       if(Inhaltsverzeichnis != NULL)
    
          fread(&Zeilen, sizeof(int), 80, Inhaltsverzeichnis);
          /*
    		 Festlegen der Anzahl von Zeilen die insgesamt gelesen werden können. 
    	  */ 
    
       for(s = 3; s < 4; s++)
       for(l = 2; l < 3; l++)
    
    	  /*
    		 Angeben der einzelnen Daten die im folgenden ausgegeben werden.
    		 Vorgang wird so oft angepasst wiederholt bis das ganze Inhaltsverzeichnis ausgegeben wurde.
    	  */
    
          printf("Datencontainer 1:	Anfang:		%d\n			Laenge:		%d Byte\n			Datensaetze:	%d\n", Zeilen[s], Zeilen[l], l/72);
    
       for(s = 5; s < 6; s++)
       for(l = 4; l < 5; l++)
    
          printf("Datencontainer 2:	Anfang:		%d\n			Laenge:		%d Byte\n", Zeilen[s], Zeilen[l]);
    
       for(s = 7; s < 8; s++)
       for(l = 6; l < 7; l++)
    
          printf("Datencontainer 3:	Anfang:		%d\n			Laenge:		%d Byte\n", Zeilen[s], Zeilen[l]);
    
       for(s = 9; s < 10; s++)
       for(l = 8; l < 9; l++)
    
          printf("Datencontainer 4:	Anfang:		%d\n			Laenge:		%d Byte\n", Zeilen[s], Zeilen[l]);
    
       for(s = 11; s < 12; s++)
       for(l = 10; l < 11; l++)
    
          printf("Datencontainer 5:	Anfang:		%d\n			Laenge:		%d Byte\n", Zeilen[s], Zeilen[l]);
    
       for(s = 13; s < 14; s++)
       for(l = 12; l < 13; l++)
    
          printf("Datencontainer 6:	Anfang:		%d\n			Laenge:		%d Byte\n", Zeilen[s], Zeilen[l]);
    
       for(s = 15; s < 16; s++)
       for(l = 14; l < 15; l++)
    
          printf("Datencontainer 7:	Anfang:		%d\n			Laenge:		%d Byte\n", Zeilen[s], Zeilen[l]);
    
       for(s = 17; s < 18; s++)
       for(l = 16; l < 17; l++)
    
          printf("Datencontainer 8:	Anfang:		%d\n			Laenge:		%d Byte\n", Zeilen[s], Zeilen[l]);
    
     return EXIT_SUCCESS;
    }
    


  • MS-Office-User schrieb:

    Vista meckert schon bei der Installationsidee. Dort wird direkt verweigert mit Hinweis auf fehlende Kompatiblität.

    eigentlich logisch würd sich ja sonst keiner die neue version kaufen...



  • @MS-Office-User:
    Du kannst bei VCE2008 dem Compiler sagen das er es als C Datei compilieren soll. Der geht im normalfall immer von C++ aus.
    Das kann man in den Projekteinstellungen angeben (bei Erweitert (oder so, bei mir ist das auf englisch "Advanced"))

    Und hier nicht ganz so mühsam (ungetestet)

    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct ContainerInfo_ {
       unsigned Offset;
       unsigned Size;
    } ContainerInfo;
    
    int main(void)
    {
       ContainerInfo containerInfo[40] = {0};
       int i = 1;
    
       FILE *Inhaltsverzeichnis;
    
       Inhaltsverzeichnis = fopen("test.dat", "r+b");
       fread(containerInfo, sizeof(ContainerInfo), 40, Inhaltsverzeichnis);
    
       for(; i < 40; ++i) {
         printf("Datencontainer %d:    Anfang:   %x\n"    
                "                      Laenge:   %u Byte\n\n", 
                i, containerInfo[i].Offset, containerInfo[i].Size);
       }
    }
    

    //Edit: Bug fix 😉
    //Edit: Copy'n'Paste bringt einfach zu viele Fehler 😛



  • evilissimo... das hier ist C, mach den bekackten _ weg 😉



  • Tim schrieb:

    evilissimo... das hier ist C, mach den bekackten _ weg 😉

    😛



  • evilissimo schrieb:

    @MS-Office-User:
    Du kannst bei VCE2008 dem Compiler sagen das er es als C Datei compilieren soll. Der geht im normalfall immer von C++ aus.
    Das kann man in den Projekteinstellungen angeben (bei Erweitert (oder so, bei mir ist das auf englisch "Advanced"))

    Das muss ich noch mal ausprobieren. Wenn ich ein neues Projekt gemacht habe, stand da jedenfalls nur C++ als Auswahlmöglichkeit, aber ich teste noch mal.

    evilissimo schrieb:

    Und hier nicht ganz so mühsam (ungetestet)

    ...
    

    Whow! 😮
    Funktioniert super, ist kurz und ich glaube ich verstehe es sogar. Vielen vielen Dank! 🙂
    Auch die Unterscheidung zwischen HEX-Wert und DEZ-Wert find ich klasse bei Anfang und Länge.
    Das mit %x und %u kannte ich nicht. Muss ich mit merken, macht so manche HEX-Konvertierung hinterher leichter.

    Eine doofe frage hätte ich aber noch für heute. Kann ich dieses Script auch als Basis nehmen um zusätzlich die Datei in die einzelnen Datencontainer zu zerlegen und einzeln als "Datenkontainer %d.dat" oder so abzuspeichern? Ich hab das auch vorher noch nicht hinbekommen, würde es aber jetzt erst mal mit Deiner scriptbasis weiter probieren.



  • Sie können den Code gerne als verwenden er ist ja für Sie gedacht gewesen 😉



  • evilissimo schrieb:

    Sie können den Code gerne als verwenden er ist ja für Sie gedacht gewesen 😉

    Vielen Dank! 🙂
    Du wäre für mich aber auch OK, fühl ich mich nicht soooo alt. 😉

    Die Einstellungen im Compilierer hab ich gefunden bei VC++2008E, nur wenn ich dann den Starte mit Vorgabe C bekomme ich im Gegensatz zu VB6.0 einen Fehler:

    1>------ Erstellen gestartet: Projekt: Evil, Konfiguration: Debug Win32 ------
    1>Kompilieren...
    1>cl : Befehlszeile warning D9035 : Die Option "Wp64" ist veraltet und wird in einer der nächsten Versionen entfernt.
    1>Inhalt_lesen_V3.c
    1>l:\c\inhalt_lesen_v3.c(16) : warning C4996: 'fopen': This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
    1>        c:\program files\microsoft visual studio 9.0\vc\include\stdio.h(237): Siehe Deklaration von 'fopen'
    1>Manifest in Ressourcen wird kompiliert...
    1>Microsoft (R) Windows (R) Resource Compiler Version 6.1.6723.1
    1>Copyright (C) Microsoft Corporation.  All rights reserved.
    1>Verknüpfen...
    1>MSVCRTD.lib(crtexew.obj) : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "_WinMain@16" in Funktion "___tmainCRTStartup".
    1>Debug\Evil.exe : fatal error LNK1120: 1 nicht aufgelöste externe Verweise.
    1>Das Buildprotokoll wurde unter "file://l:\c\Debug\BuildLog.htm" gespeichert.
    1>Evil - 2 Fehler, 2 Warnung(en)
    ========== Erstellen: 0 erfolgreich, Fehler bei 1, 0 aktuell, 0 übersprungen ==========
    

    Änder ich fopen zu fopen_s klappt es auch nicht:

    1>------ Erstellen gestartet: Projekt: Evil, Konfiguration: Debug Win32 ------
    1>Kompilieren...
    1>cl : Befehlszeile warning D9035 : Die Option "Wp64" ist veraltet und wird in einer der nächsten Versionen entfernt.
    1>Inhalt_lesen_V3.c
    1>l:\c\inhalt_lesen_v3.c(16) : warning C4047: 'Funktion': Anzahl der Dereferenzierungen bei 'FILE **' und 'char [9]' unterschiedlich
    1>l:\c\inhalt_lesen_v3.c(16) : warning C4024: 'fopen_s': Unterschiedliche Typen für formalen und übergebenen Parameter 1
    1>l:\c\inhalt_lesen_v3.c(16) : error C2198: "fopen_s": Nicht genügend Argumente für Aufruf.
    1>l:\c\inhalt_lesen_v3.c(16) : warning C4047: '=': Anzahl der Dereferenzierungen bei 'FILE *' und 'errno_t' unterschiedlich
    1>Das Buildprotokoll wurde unter "file://l:\c\Debug\BuildLog.htm" gespeichert.
    1>Evil - 1 Fehler, 4 Warnung(en)
    ========== Erstellen: 0 erfolgreich, Fehler bei 1, 0 aktuell, 0 übersprungen ==========
    

Anmelden zum Antworten