Binär dateien in einer std::list?



  • Hey @all,

    ich habe vor text informationen, und jetzt auch bild informationen zu lesen, und dieser in einem eigenen Dateiformat zu speichern.

    Mein Problem liegt eigentlich nur an den Binär dateien. sei es PDF oder jpg, oder was auch immer.

    ich würde die Dateien wie folgt einlesen:

    struct FileContent {
    	std::string content;
    	unsigned int content_size;
    };
    
    std::map<int, std::list<FileContent> > ml;
    std::list<FileContent> sl;
    
    fstream file(input_filename, ios::in | ios::binary);
    char buffer[1024];
    while(file.read(buffer, 1024)) {
    	struct FileContent fc;
    	memset(&fc, '\0', sizeof(fc));
    
    	memset(&buffer, '\0', 1024);
    	file.read(buffer, 1024);
    	fc.content.append(buffer, file.gcount());
    	fc.content_size = file.gcount();
    	sl.push_back(fc);
    }
    m[0] = sl;
    

    Das schreiben der dateien würde wieder wie folgt aussehen:

    fstream file(output_filename, ios::out | ios::binary);
    for(std::map<int, std::list<FileContent> >::iterator mlIter = ml.begin(); mlIter != ml.end(); ++mlIter) {
    	for(std::list<FileContent>::iterator slIter = (*mlIter).second.begin(); slIter != (*mlIter).second.end(); ++slIter) {
    		unsigned int size = (*slIter).content_size;
    		file.write(reinterpret_cast<const char*>(&(*slIter).content), (*slIter).content_size);
    	}
    }
    file.close();
    

    Mein Problem ist nun das er entweder nicht richtig liest bzw. nicht richtig schreibt. Habe das ganze mal mit einem simplen bild ausprobiert. nur meine geschriebene Version lässt sich nicht mehr öffnen.

    Hat jemand rat?

    Vor hätte ich das ich beispielsweise normale benutzer informationen speichern kann (Name, Geburtsdatum usw.) und dann eventuell noch ein Bild des benutzers.

    Lg freeze



  • freeze schrieb:

    struct FileContent {
    	std::string content;
    	unsigned int content_size;
    };
    
    ...
    struct FileContent fc;
    memset(&fc, '\0', sizeof(fc));
    ...
    

    Das ist ganz übel - mit dem memset() überschreibst du die Kontrollinformationen des Strings 'content', danach kannst du nicht mehr vorhersagen, wie er sich verhalten wird.
    (Merke: Greife niemals über Low-Level-Funktionen (wie memset()) auf voll ausgewachsene Klassenobjekte zu - damit umgehst du die Datenkapselung von C++ und zerstörst im Ernstfal wichtige Invarianten der Klasse)

    Der zweite (logische) Fehler in deinem Code ist, daß gcount() nur die Zeichenzahl aus dem letzten read()-Befehl zurückgibt. Das heißt, dein fc.content_size enthält eine zu kleine Größenangabe.
    (btw, content_size benötigst du überhaupt nicht - an die tatsächliche Größe der eingelesenen Datei kommst du per fc.content.size() )



  • Hallo,

    also ich habe das jetzt mal so umgeschrieben

    char buffer[1024];
    while(file.read(buffer, 1024)) {
    	struct FileContent fc;
    
    	memset(&buffer, '\0', 1024);
    	file.read(buffer, 1024); 
    	fc.content = buffer; //.append(buffer, file.gcount());
    	//fc.content_size = file.gcount();
    	sl.push_back(fc);
    }
    ml[0] = sl;
    

    und

    fstream file(output_filename, ios::out | ios::binary);
    for(std::map<int, std::list<FileContent> >::iterator mlIter = ml.begin(); mlIter != ml.end(); ++mlIter) {
        for(std::list<FileContent>::iterator slIter = (*mlIter).second.begin(); slIter != (*mlIter).second.end(); ++slIter) {
            unsigned int size = (*slIter).content_size;
            file.write(reinterpret_cast<const char*>(&(*slIter).content), (*slIter).content.size());
        }
    }
    file.close();
    

    Jetzt wird die zu schreibende Datei aber noch kleiner 😞

    Ich komme einfach nicht auf das Problem

    Lg freeze



  • Erstens: std::string interpretiert das \0 (was in binären Daten durchaus vorkommen kann) als String-Ende, außer du gibst die Datengröße explizit vor:

    fc.content.assign(buffer,file.gcount);
    

    Zweitens: Wenn du einen string per reinterpret_cast als char-Array uminterpretierst, bekommst du nur Müll heraus. Für die Umwandlung, die du suchst, hat string die Methode c_str() oder data():

    file.write(slIter->content.data(), slIter->content.size());
    

    PS: Die STL-Iteratoren haben auch op-> überladen, da kannst du statt (*Iter).irgendwas auch Iter->irgendwas schreiben (letzteres sieht imho übersichtlicher aus).


Anmelden zum Antworten