Festplattenimage einlesen C/C++



  • Hallo Leute,

    ich habe folgendes Problem. Wie kann ich am einfachsten bzw. effizientesten ein mehrere GB großes Festplattenimage zur Weiterverarbeitung in C++ einlesen? Letzten Endes möchte ich das Image auf diverse Bytestrukturen untersuchen. Hat damit jemand Erfahrung gemacht bzw. kennt evtl. eine Library?

    Vielen Dank und Grüße
    tommy



  • tommy0816 schrieb:

    Wie kann ich am einfachsten bzw. effizientesten ein mehrere GB großes Festplattenimage zur Weiterverarbeitung in C++ einlesen? Letzten Endes möchte ich das Image auf diverse Bytestrukturen untersuchen.

    Wie wäre es hiermit?

    #include <algorithm>
    #include <fstream>
    #include <iterator>
    #include <vector>
    
    int main()
    {
    	std::ifstream file("xyz.img",std::ios_base::binary);
    	std::vector<unsigned char> image;
    	file >> std::noskipws;
    	std::copy( std::istream_iterator<unsigned char>(file), std::istream_iterator<unsigned char>(), std::back_inserter(image) );
    }
    

  • Mod

    out schrieb:

    tommy0816 schrieb:

    Wie kann ich am einfachsten bzw. effizientesten ein mehrere GB großes Festplattenimage zur Weiterverarbeitung in C++ einlesen? Letzten Endes möchte ich das Image auf diverse Bytestrukturen untersuchen.

    Wie wäre es hiermit?

    #include <algorithm>
    #include <fstream>
    #include <iterator>
    #include <vector>
    
    int main()
    {
    	std::ifstream file("xyz.img",std::ios_base::binary);
    	std::vector<unsigned char> image;
    	file >> std::noskipws;
    	std::copy( std::istream_iterator<unsigned char>(file), std::istream_iterator<unsigned char>(), std::back_inserter(image) );
    }
    

    Das ist definitiv nicht effizient, sondern eher die ineffizienteste Art (abgesehen von absichtlichen Warteschleifen im Code). Nimm read und Konsorten. Als Datenstruktur kommt es drauf an, wie groß das Image ist und wie groß der Arbeitsspeicher ist. Prinzipiell klingt die Suche nach Mustern nach einem Fall für vector, eventuell deque (falls man an der Arbeitsspeicherkapazität kratzt). Festplattenimages sind aber in der Regel wesentlich größer als ein paar Gigabytes, da wird man sich wohl fragen müssen, ob es nicht auch in Frage käme, das Image stückchenweise zu betrachten. Ganz einlesen wird in der Regel aus technischen Gründen nicht möglich sein.



  • SeppJ schrieb:

    Nimm read und Konsorten.

    Meinst du so?

    int main()
    {
    	std::ifstream file("xyz.img",std::ios_base::binary);
    
    	file.seekg(0,std::ios_base::end);
    	unsigned length = file.tellg();
    	file.seekg(0,std::ios_base::beg);
    
    	char* image = new char[length];
    	file.read(image,length);
    }
    

  • Mod

    Ich verstehe zwar nicht, wieso du keinen vector nimmst, aber im Prinzip ja.



  • Würde das Ganze blockweise einlesen und auf Muster prüfen. Du musst allerdings den Sonderfall betrachten, dass ein Blockwechsel mitten im Muster auftreten kann.



  • Wieso genau musst du unbedingt das ganze Image in den Speicher laden? Wie schon angedeutet wurde, wird man wohl davon ausgehen müssen, dass so ein Festplattenimage potentiell wesentlich größer ist als der verfügbare Arbeitsspeicher!?



  • SeppJ schrieb:

    Ich verstehe zwar nicht, wieso du keinen vector nimmst, aber im Prinzip ja.

    read will doch ein char* als Argument. vector kann ich dann doch erst einsetzen, nachdem ich read gemacht habe.



  • Sepp meint damit sowas:

    #include <vector>
    #include <fstream>
    
    int main()
    {
        // open file
        std::ifstream file("hdd.img", std::ios::binary);
    
        // determine size
        file.seekg(0,std::ios_base::end);
        unsigned length = file.tellg();
        file.seekg(0,std::ios_base::beg);
    
        // allocate buffer
        std::vector<char> buffer(length);
    
        // read data
        file.read(&(buffer[0]), length);
    }
    

    Vorteil ist hier, dass der vector den Speicher selbstständig wieder freigibt.
    Du solltest aber weiterhin beachten, dass eben Festplatten-Images meistens größer sind als dein Arbeitsspeicher.
    (Abgesehen davon, dass unsigned int sowohl bei x86 als auch x86_64 lediglich 32 Bit groß ist. Ist dein Image größer, so werden bei deiner length einfach die überschüssigen Bits weggeschnitten.)

    Sinnvoll wäre es, sich mit den Datenstrukturen auf einer Festplatte zu befassen (MBR, Dateisystem-Tabellen usw.). Diese enthalten Adressen von anderen wichtigen Datenblöcken im Image, sodass man gezielt nur die relevanten Blöcke laden kann.



  • Da das Einlesen der Datei vermutlich von einem langsamen Medium geschieht, ist das A und O hier die Minimierung der Dateizugriffe. Wenn ich

    tommy0816 schrieb:

    Letzten Endes möchte ich das Image auf diverse Bytestrukturen untersuchen.

    richtig verstehe, empfiehlt sich daher eine Vorgehensweise, wie sie beispielsweise von GNU grep benutzt wird (siehe hier): Nur die Bytes holen, die man auch wirklich ankucken will. Habe ich beispielsweise eine 512 Byte lange Pattern und stelle fest, dass das Byte 512 Byte hinter meiner Position nicht passt, kann ich gleich 512 Byte weiterspringen.

    Es gibt eine Reihe von Algorithmen, die sich für diesen Zweck anbieten und ein solches Vorgehen erlauben. GNU grep benutzt Boyer-Moore, und das könnte auch für dich eine gute Wahl sein. Letztendlich kann ich das aber aus der Enternung natürlich nicht mit Bestimmtheit sagen.


  • Mod

    DrakoXP schrieb:

    (Abgesehen davon, dass unsigned int sowohl bei x86 als auch x86_64 lediglich 32 Bit groß ist. Ist dein Image größer, so werden bei deiner length einfach die überschüssigen Bits weggeschnitten.)

    std::streamsize FTW!


Anmelden zum Antworten