Binärdatei einlesen und wieder ausgeben...
-
Hi Leute, hab ein kleines Problem.
Als Ausgang existiert eine Binärdatei.
In dieser stehen der Reihe nach Datensätze, die in Structs eingelesen werden sollen:#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <math.h> #include <time.h> #define CHAR_BLOCK (10*sizeof (char)) #define FILENAME "mp3s" typedef struct mp3 Mp3; static Mp3* head = NULL, // points to first element *last = NULL; // saves pointer to last addet element struct mp3 { unsigned id; double rating; unsigned cont_length; //Länge insgesammt der Nachfolgenden Buchstaben von char* titel; //titel bis comment char* name; char* interprete; char* comment; Mp3* prev, *next; };
Des Problem is, dass zuerst in der Binär die Anzahl aller der Datensätze steht, dann id1, rating1, Cont_length1, dann id2, rating2 usw. und erst am Schluss alle Strings (titel1, name1, interprete1, comment1, titel2, interprete2...)
Wie müsste eine Programm ausschauen, welches die einzelnen Informationen ausliest, sie in doppelt verkettete Listen Speichert und schlussendlich wieder in der ursprünglischen Reihenfolge in eine Binärdatei speichert.
Nur zum besseren Verständniss: In der doppelt verketteten Liste sollen die Structs dann vom Benutzer geändert werden können, aba diese Funktionen habe ich bereits...
Hoffe auf eine baldige Antwort
Lg. Jakob
-
Hi,
ich bin mir nicht ganz sicher, ob ich dich richtig verstanden habe, aber vllt so:
Lese Anzahl an Datensätzen nach i Setzte a = 0 erzeuge Structpointer p; Solange a < i Erzeuge struct x lese id und speichere in x lese rating und speichere in x ... speicher x in verkettete Liste (nach p) lasse p auf x zeigen a++ Loop setzte a = 0 lasse p auf head zeigen Solange a < i lese titel und speichere in *p lese name und speichere in *p ... lasse p auf p->next zeigen a++ Loop
Also im Prinzip einfach zweimal durch die Liste durchgehen wäre eine Methode. Speichern sollte genauso funktionieren.
-
Also deine Arbeit (die mal nicht so aussieht wie eine Hausaufgabe) wird dir hier sicher nicht komplett fertig gemacht, schreib deinen Code mal hin, die Fehler könnte man hier dann abstellen. Du hast vergessen zu erwähnen, wie deine Binärzahl am Dateibeginn denn spezifiziert ist, d.h. wieviele Bytes und Endian.
-
Also so weit bin ich mal gekommen, doch wo es zum einlesen in die Structs kommt hänge ich...
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <math.h> #include <time.h> #define CHAR_BLOCK (10*sizeof (char)) #define FILENAME "mp3s" typedef struct mp3 Mp3; static Mp3* head = NULL, // points to first element *last = NULL; // saves pointer to last addet element struct mp3 { unsigned id; double rating; unsigned cont_length; char* titel; char* name; char* interprete; char* comment; Mp3* prev, *next; }; typedef struct // Configuration struct { char magic_number [5]; } Conf; //----------------------------------------------------------------------------- /// The error_1-function. /// prints error-code 1 /// /// @ return: always -1; // int errorOne() { printf ("usage: ex3 -o=dbfile\n"); return -1; } //----------------------------------------------------------------------------- /// The error_2-function. /// prints error-code 2 /// /// @ return: always -2; // int errorTwo() { printf ("out of memory\n"); return -2; } //----------------------------------------------------------------------------- /// The error_3-function. /// prints error-code 3 /// /// @ return: always -3; // int errorThree(char* filename) { printf ("error: cannot read dbfile [%s]\n", filename); return -3; } //----------------------------------------------------------------------------- /// The error_4-function. /// prints error-code 4 /// /// @ return: always -4; // int errorFour(char* filename) { printf ("error: cannot read configfile [%s]\n", filename); return -4; } ///----------------------------------------------------------------------------- /// The funcRead-function. /// reads input and saves it into an array /// /// @return (-2), if there is no more Memory availible /// (-1), if there was no input /// otherwise (0) /// @param ptr_text pointer to text array with the input /// @param ptr_length pointer to length of the input-string /// int funcRead(char** ptr_text, int* ptr_length) { int org_counter = 0; int block_counter = 1; // number of memoryblocks needed char temp_sign; char *temp_ptr = malloc(CHAR_BLOCK); if (temp_ptr == NULL) // break condition: out of memory { free(temp_ptr); return errorTwo(); } char *text_array = temp_ptr; for (org_counter = 0; (temp_sign = getchar()) != '\n'; org_counter++) { if (org_counter<(block_counter * CHAR_BLOCK)) // checks if array is full { text_array [org_counter] = temp_sign; // saves input-character in array } else { block_counter++; temp_ptr = realloc(temp_ptr, block_counter * CHAR_BLOCK); if (temp_ptr == NULL) // break condition: out of memory { free(text_array); free(temp_ptr); return errorTwo(); } else text_array = temp_ptr; text_array [org_counter] = temp_sign; } } if (org_counter == 1) { free(temp_ptr); return errorOne (); } text_array = realloc (text_array, (org_counter)*sizeof (char)); // limits allocated memory to textsize *ptr_text = text_array; *ptr_length = org_counter; return 0; } int read_bin (char* argv, Conf *config) { if (argv == NULL) return errorOne(); // checks if user entered command for configfile if ((argv[0] != '-')||(argv[1] != 'o')||(argv[2] != '=')) return errorOne(); // checks if user entered '-c=' before filename int pos = 3; // position in argv for filename (after -c=) char *filename; // array for filename of configfile int length_filename = 0; // length of array filename int block_counter = 1; // number of memoryblocks needed char *temp_ptr = malloc(CHAR_BLOCK); // pointer for memory allocation if (temp_ptr == NULL) // break condition: out of memory { free(temp_ptr); return errorTwo(); } filename = temp_ptr; while (argv[pos]!='\0') { if (length_filename < (block_counter * CHAR_BLOCK)) filename[length_filename++] = argv[pos++]; else { block_counter++; temp_ptr = realloc(temp_ptr, block_counter * CHAR_BLOCK); if (temp_ptr == NULL) // break condition: out of memory { free(filename); free(temp_ptr); return errorTwo(); } else filename = temp_ptr; filename[length_filename++] = argv[pos++]; } filename = realloc (filename, (length_filename+1)*sizeof (char)); } FILE *configfile; configfile = fopen(filename,"r"); if (configfile == NULL) { return errorThree(filename); } fread (config, sizeof config, 5, configfile); // reads out of configfile into struct config (type Conf) if (((*config).magic_number[0] != 'E')&&((*config).magic_number[1] != 'P')&& ((*config).magic_number[2] != 'D')&&((*config).magic_number[3] != 'B')) // checks if MagicNumber is right { free(filename); free(temp_ptr); return errorFour(filename); } return 0; } int main (int argc, char* argv[]) { Conf config; int return_value = read_bin(argv[1], &config); if (return_value != 0) return return_value; return 0; }
-
Also ich habe mal eine Funktion etwas reduziert:
int read_bin (char* filename, Conf *config) { FILE *configfile; if( !config || !filename|| strncmp(filename,"-c=",3) ) return errorOne(); filename+=3; configfile = fopen(filename,"rb"); if (configfile == NULL) { return errorThree(filename); } if( !fread(config->magic_number,4,1,configfile) || strncmp(config->magic_number,"EPDB",4) ) { return errorFour(filename); } ... return 0; }
Die andere Funktion funcRead ist ebenso verbesserungswürdig und dann lesbarer/wartbarer.
Du hast doch geschrieben, dass am Anfang die Zahl der Datensätze steht, soll denn "EPDB" die Anzahl sein?
Die Leseschleife ist dann relativ einfach, aber da die Struktur nicht zusammenhängend lesbar ist, würde ich zunächst mal in ein Struktur-Array lesen und danach dann deine verkettete Liste aufbauen.
-
Hi!
Also in der Binärdatei muss am Anfang der "Schlüssel" EPDB stehen,
dann erst die Anzahl der Datensätze...Wie genau soll ich des mit dem Struktur-Array verstehen?
-
Dass soll bedeuten, dass ich für diesen Fall ein Array als Zwischenlesepuffer für einfacher handhabbar halte als direkt in die gewünschte Zielliste zu schreiben.
Zu Anfang hattest du noch gesagtDes Problem is, dass zuerst in der Binär die Anzahl aller der Datensätze steht,
jetzt sagst du, "EPDB" steht am Anfang, was denn nun?
Steht hinter "EPDB" noch ein '\0', wie ist die Anzahl abgelegt (meine Frage oben),...
-
Also, ja es steht zuerst EPDP in der Datei, dann die Anzahl der gesammten Structs (also wie viele IDs etc...) und dann die bereits genannte Reihenfolge.
So weit bin ich mal gekommen, aba es scheitert jez an der Einlesung der Binärdatei in ein Array:
int read_bin (char* filename, Conf *config, char** input) { FILE *configfile; if( !config || !filename|| strncmp(filename,"-o=",3) ) return errorOne(); filename+=3; configfile = fopen(filename,"rb"); if (configfile == NULL) { return errorThree(filename); } if( !fread(config->magic_number,4,1,configfile) || strncmp(config->magic_number,"EPDB",4) ) { return errorFour(filename); } int written = fwrite (input, sizeof(configfile), 0, configfile); printf ("geschrieben: %d", written); //debug!!!!!! fclose(configfile); int count; for (count = 0; count <= written; count++) // debug!!!!! { printf ("%c", input [count]); } return 0; } int main (int argc, char* argv[]) { Conf config; char* in_string; int return_value = read_bin(argv[1], &config, &in_string); if (return_value != 0) return return_value; return 0; }
-
Du hast das Prinzip des Einlesens aus der Datei in deine Wunschliste nicht verstanden. Aufgrund der unglücklichen (laienhaften?) Strukturierung der beschriebenen Binärdatei liegen die Elemente eines Strukturelements nicht hintereinander, d.h. man muss ständig auf das korrekte Element in der Liste navigieren. Das geht mit Arrays am Einfachsten:
int read_bin (char* filename, Conf *config, Mp3** a) { unsigned z,i; FILE *configfile; if( !config || !filename|| strncmp(filename,"-o=",3) ) return errorOne(); filename+=3; configfile = fopen(filename,"rb"); if (configfile == NULL) { return errorThree(filename); } if( !fread(config->magic_number,4,1,configfile) || strncmp(config->magic_number,"EPDB",4) ) { return fclose(configfile),errorFour(filename); } if( !fread(&z,sizeof z,1,configfile) || !(*a = malloc(z*sizeof**a)) ) return fclose(configfile),-1; printf("\n%u Elemente werden gelesen...",z); for(i=0;i<z;++i) if( !fread(&(*a)[i].id,sizeof (*a)[i].id,1,configfile) ) return fclose(configfile),-1; for(i=0;i<z;++i) if( !fread(&(*a)[i].rating,sizeof (*a)[i].rating,1,configfile) ) return fclose(configfile),-1; for(i=0;i<z;++i) if( fread(&(*a)[i].content_length,sizeof (*a)[i].content_length,1,configfile) ) { if( !((*a)[i].titel=calloc(1,(*a)[i].content_length+1) ) return fclose(configfile),-1; if( !fread((*a)[i].titel,(*a)[i].content_length,1,configfile) ) return fclose(configfile),-1; } fclose(configfile); return z; } int main (int argc, char* argv[]) { Conf config; Mp3 *a = 0; int zahl = read_bin(argv[1], &config, &a); if( zahl>=0 ) { printf("\nEs wurden %d Elemente gelesen",zahl); while( zahl-- ) printf("\n%u %f %s %s %s %s",a[zahl].id,a[zahl].rating,a[zahl].titel,a[zahl].name,a[zahl].interpret,a[zahl].comment); } realloc(a,0); return 0; }
Diverses fehlt natürlich noch, auch habe ich einige Annahmen an die ominöse Dateistruktur gemacht. Den Rest machst du jetzt mal selbst.
-
Wozu ist denn diese hier?
int written = fwrite (input, sizeof(configfile), 0, configfile); printf ("geschrieben: %d", written); //debug!!!!!!
Du liest doch aus der Datei; Oder?
Ansonsten lifert dir sizeof(configfile) die Größe der Variablen configfile. Da configfile ein Zeiger auf FILE ist kommt wahrscheinlich 4 (bei 32-bit) raus.