Eigene Resourcedatei ist nur ein paar Bytes groß



  • Zu der Frage hier https://www.c-plusplus.net/forum/341619
    habe ich nun ein eigenständiges Programm geschrieben, was mir meine Assets in eine Datei schreibt (binär). Zuerst musste ich mich mit diversen Fehlermeldungen rumschlagen und habe es dann aber zum laufen bekommen. Das Problem ist aber, dass die Resourcedatei nur ein paar Bytes groß ist. Ich habe extra ein Bild in den textures Ordner gelegt, damit er diese Datei ließt und in die resource.res datei schreibt. Kann bitte wer mal über meinen Code drüberschauen? Das wäre sehr nett.

    #include <vector>
    #include <string>
    #include <fstream>
    #include <iostream>
    #include <boost/filesystem.hpp>
    
    using namespace boost::filesystem;
    
    struct ResourceFile
    {
        std::vector<std::pair<char*, std::string>> textures;
        std::vector<std::pair<char*, std::string>> sounds;
    };
    
    char* load(std::string file) 
    {
        long size;
        ifstream in;
        in.open(file, std::ios::binary | std::ios::in | std::ios::ate);
        size = in.tellg();
        char* data = new char[size];
        in.seekg(0, std::ios::beg);
        if (!in.read(data, size))
            std::cout << "Cant open File " << file << std::endl;
        in.close();
        return data;
    }
    
    int main(int argc, char **argv) {
        ResourceFile Data;
    
        path readDir(argv[1]);
        path writeFile(argv[2]);
        std::vector<path> Dirs;
    
        if (ifstream((std::string)argv[2] + "resources.res"))
        {
            path d((std::string)argv[2] + "resources.res");
            remove(d);
        }
    
        if (exists(readDir))
        {
            directory_iterator itr_end_dirs;
            for (directory_iterator itr(readDir); itr != itr_end_dirs; itr++)
            {
                std::string str = argv[1] + itr->path().filename().string();
                path p(str);
                Dirs.push_back(p);
            }
    
            for (std::vector<path>::const_iterator itr = Dirs.begin(); itr != Dirs.end(); itr++)
            {
                directory_iterator itr_end;
                for (directory_iterator itr_d(Dirs.at(itr - Dirs.begin())); itr_d != itr_end; itr_d++)
                {
                    if (Dirs.data()->filename().string() == "textures")
                        Data.textures.push_back(std::make_pair(load(itr_d->path().string()), itr_d->path().filename().string()));
                    else if (Dirs.data()->filename().string() == "sounds")
                        Data.sounds.push_back(std::make_pair(load(itr_d->path().string()), itr_d->path().filename().string()));
                }
            }
    
        }
        else
            std::cout << "Couldnt find Directory to read from." << std::endl;
    
        std::string target = (std::string)argv[2] + "resource.res";
        ofstream out;
        out.open(target, std::ios::binary | std::ios::out);
        out.write((char*)&Data, sizeof(Data));
        out.close();
    
        return 0;
    }
    


  • out.write((char*)&Data, sizeof(Data));
    

    So kannst du keinen Vector serialisieren...



  • Th69 schrieb:

    out.write((char*)&Data, sizeof(Data));
    

    So kannst du keinen Vector serialisieren...

    Data ist kein Vektor sondern ein Struct. Hab bisher nur Tipps im Internet gefunden die das so machen. Jemand eine Idee oder ein Link?



  • Bennisen schrieb:

    Data ist kein Vektor sondern ein Struct

    Und woraus besteht die Struktur?



  • manni66 schrieb:

    Bennisen schrieb:

    Data ist kein Vektor sondern ein Struct

    Und woraus besteht die Struktur?

    aus 2 Vektoren 🙂



  • Genau, und die Adresse des Strukturobjekts (&Data) ist in dem Fall die Adresse des ersten Vektorobjekts (&textures).

    Das Vektorobjekt besteht aber aus mehr als nur den Daten, zB. Länge, und es gibt keine Garantie, wie es (die Klasse std::vector) genau aufgebaut ist.
    An &Data steht also vielleicht ein Integer (size) und ein Pointer (data).
    Das willst du bestimmt nicht schreiben.

    Was du suchst ist std::vector::data.



  • Hi schrieb:

    Genau, und die Adresse des Strukturobjekts (&Data) ist in dem Fall die Adresse des ersten Vektorobjekts (&textures).

    Das Vektorobjekt besteht aber aus mehr als nur den Daten, zB. Länge, und es gibt keine Garantie, wie es (die Klasse std::vector) genau aufgebaut ist.
    An &Data steht also vielleicht ein Integer (size) und ein Pointer (data).
    Das willst du bestimmt nicht schreiben.

    Was du suchst ist std::vector::data.

    Ich verstehe was du meinst, hatte das irgendwie nicht ganz bedacht. Hab mal was über Vector Serialization gelesen. Scheint nicht mal einfach so machbar zu sein. Werde mich wohl auch da noch hinterklemmen müssen.



  • Ups, ich seh grad du hast ja std::pair im vector.
    Dann kannst du nicht einfach textures.data() schreiben. Das ginge aber zB. bei einem std::vector<char>.
    Du musst hier auf deine char* und std::string manuell zugreifen.



  • Hi schrieb:

    Ups, ich seh grad du hast ja std::pair im vector.
    Dann kannst du nicht einfach textures.data() schreiben. Das ginge aber zB. bei einem std::vector<char>.
    Du musst hier auf deine char* und std::string manuell zugreifen.

    Ja hab das dann auch gemerkt. Hab nun den ofstream überladen.

    ofstream &operator << (ofstream &stream, std::vector<std::pair<char*, std::string>> &vec)
    {
        size_t vec_size = vec.size();
        stream << vec_size;
    
        for (size_t i = 0; i < vec_size; i++)
        {
            stream << vec[i].first << vec[i].second;
        }
        return stream;
    }
    

    Hab das nun auf mehrere Dateien aufgeteilt. Aber leider stimmt da immernoch irgendwas nicht. Die Dateien sind einfach noch zu klein die erzeugt werden.

    std::string targetTex = (std::string)argv[2] + "textures.res";
        std::string targetSou = (std::string)argv[2] + "sounds.res";
        ofstream outTex, outSou;
        outTex.open(targetTex, std::ios::binary | std::ios::out);
        outSou.open(targetSou, std::ios::binary | std::ios::out);
        outTex << textures;
        outSou << sounds;
        outTex.close();
        outSou.close();
    

    edit: Ich habe die Befürchtung, dass die Daten irgendwie nicht im Vektor landen.



  • binary mode und formatted i/o solltest du nicht mischen.
    Verwende also nur .write().
    Bei std::string brauchst du dann .c_str().

    Bennisen schrieb:

    Ich habe die Befürchtung, dass die Daten irgendwie nicht im Vektor landen.

    Das kannst du ganz einfach zB. mit dem Debugger prüfen.



  • Hab jetzt mal mit dem Debugger gecheckt was bei lesen der Dateien zurückgegeben wird. Ich lese ja mit boost Verzeichnisse aus und lese alle Dateien binär ein und will sie dann im Vector speichern. Bei dieser Funktion.

    char* load(std::string file) 
    {
        std::streampos size;
        ifstream in;
        in.open(file, std::ios::binary | std::ios::in | std::ios::ate);
        size = in.tellg();
        char* data = new char[size];
        in.seekg(0, std::ios::beg);
        if (!in.read(data, size))
            std::cout << "Cant open File " << file << std::endl;
        in.close();
        return data;
    }
    

    Steht in dem Returnwert zB bei einer Datei nur das drin -119'\211'
    Sieht für mich nicht so aus, dass er die komplette Datei eingelesen hat. Normal müsste doch viel mehr dadrin stehen.



  • Bennisen schrieb:

    Ich lese ja mit boost Verzeichnisse aus

    Schon mal von boost::serialization gehört?

    Bennisen schrieb:

    Steht in dem Returnwert zB bei einer Datei nur das drin -119'\211'
    Sieht für mich nicht so aus, dass er die komplette Datei eingelesen hat. Normal müsste doch viel mehr dadrin stehen.

    Wenn deine Fehlerbehandlung nicht so kacke wäre, hättest du schon mehr Infos.



  • Woher willst du nachher noch das Ende von char* erkennen?
    Das was du so einliest, wird nicht nullterminiert.
    Gibst du die Ressourcen, die du mit new anlegst überhaupt wieder frei?
    Warum nimmst du nicht einfach einen vector?



  • Ich liebe und hasse ja den Umgangston in fast jedem Forum. Spart euch jede weitere Mühe, weiß noch nicht wie, aber irgendwie kriege ich das hin. Trotzdem danke für bisherige Unterstützung.



  • Och, wir nehmen die Noobs halt gerne mal 'n bisschen hart ran. Aber wirklich nur 'n bisschen!

    Hast du denn die letzten beiden Posts verstanden? Dann müsstest du jetzt schon weiterkommen.



  • Das ist mir alles ehrlich gesagt zuviel aufwand. Ich verwende jetzt einfach das Resourcing von QT.



  • [quote="Bennisen"]

    std::string targetTex = (std::string)argv[2] + "textures.res";
    

    Das halte ich auch für sehr gewagt 😮



  • [quote="DocShoe"]

    Bennisen schrieb:

    std::string targetTex = (std::string)argv[2] + "textures.res";
    

    Das halte ich auch für sehr gewagt 😮

    Warum?



  • Weil argv[2] ein const char* ist und kein std::string . Der C-style cast führt keine Konvertierung aus und verhält sich wie ein reinterpret_cast . Oder etwa nicht?

    Ächz, diese ganzen Sonderfälle machen mich fertig o.O

    Bei einer gültigen Konvertierung verhält sich der C-cast wie ein static_cast , ansonsten eher wie ein reinterpret_cast ?



  • DocShoe schrieb:

    Weil argv[2] ein const char* ist und kein std::string . Der C-style cast führt keine Konvertierung aus und verhält sich wie ein reinterpret_cast . Oder etwa nicht?

    Ächz, diese ganzen Sonderfälle machen mich fertig o.O

    Bei einer gültigen Konvertierung verhält sich der C-cast wie ein static_cast , ansonsten eher wie ein reinterpret_cast ?

    Nein, es wäre wie:

    std::string targetTex = std::string(argv[2]) + "textures.res";
    


  • manni66 schrieb:

    DocShoe schrieb:

    Weil argv[2] ein const char* ist und kein std::string . Der C-style cast führt keine Konvertierung aus und verhält sich wie ein reinterpret_cast . Oder etwa nicht?

    Ächz, diese ganzen Sonderfälle machen mich fertig o.O

    Bei einer gültigen Konvertierung verhält sich der C-cast wie ein static_cast , ansonsten eher wie ein reinterpret_cast ?

    Nein, es wäre wie:

    std::string targetTex = std::string(argv[2]) + "textures.res";
    

    Sicher? Denn das 2. ist was ganz was anderes als das erste.
    Ich glaub kaum dass bei einem (std::string)argv[2] ein std::string constructor aufgerufen wird


Anmelden zum Antworten