Datei bitweise einlesen



  • Hallo zusammen,

    ich suche verzweifelt eine Möglichkeit die Bits oder Bytes einer beliebigen Datei einzulesen. Ob im Binärsystem oder im Hexadezimalsystem ist nicht relevant. Ich weiß das ich mit

    ifstream.open("test.jpg" ios::binary);
    

    Dateien einlesen kann. Aber wie komme ich an den Binär oder Hexcode der Datei?
    Vereinfacht gesagt suche ich eine Möglichkeit eine Datei wie in einem Hexeditor auslesen zu können.

    Hätte da jemand eine Idee für mich?

    Bin für jede Hilfe dankbar.

    PS: Hintergrund der Geschichte ist, das ich einen Codierer schreiben will, der eine beliebige Datei Base64-codiert ausgeben kann.



  • Nö, genau so liest man eine Datei NICHT ein.
    Das geht so:

    std::ifstream is("bla.txt", some_flags);
    


  • ich weiß das ich erst eine variable des typs ifstream erzeugen muss. Aber du hast Recht aus dem ersten Post kommt das nicht klar heraus.



  • Nein, du sollst die Argumente im Konstruktor übergeben. open() gibts nicht.



  • verzweilter anfänger schrieb:

    PS: Hintergrund der Geschichte ist, das ich einen Codierer schreiben will, der eine beliebige Datei Base64-codiert ausgeben kann.

    Einzelzeichenweise lesen, dann Bitoperationen: &, |, ~, ^, <<, >> anwenden.



  • Es gibt die Funktion .open aus dem fstream-header nicht?

    ifstream is;
    is.open("test.jpg" ios::binary);
    //tu was mit den Daten
    is.close();
    

    Diese Zeilen können nicht kompiliert werden?



  • Die Funktionen sind scheiße, du solltest sie nicht verwenden, das wollte ich damit sagen.



  • Dein Problem ist nicht das Einlesen, sondern das Ausgeben. Du musst angeben, wie der Wert zu interpretieren und auszugeben ist - wenn du einen int an cout gibst, erhälst du ja den String des Werts und nicht das ASCII-Zeichen.

    Jetzt hast du zwei Möglichkeiten:

    1. Du gibst cout (ich vermute einfach mal, das ist deine Standardausgabe) für jeden Wert mit, wie er zu interpretieren ist (mithilfe der Bezeichner bin , oct , dec und hex ):

    #include <iostream>
    using namespace std;
    
    int main()
    {
        //Ausgabe aller druckbaren ASCII-Zeichen in Binär, Oktal und Hexadezimal.
        for(int i=32;i<=127;i++)
            cout<<i<<" = "<<bin<<i<<" | "<<i<<" = "<<oct<<i<<" | "<<i<<" = "<<hex<<i<<"\n";
        return 0;
    }
    

    2. Oder, wenn du nur ein bestimmtes Format brauchst, kannst du auch mit setf arbeiten:

    #include <iostream>
    using namespace std;
    
    int main()
    {
        cout.setf(ios::hex);
        //Ausgabe aller druckbaren ASCII-Zeichen in Hexadezimal.
        for(int i=32;i<=127;i++)
            cout<<i<<"\n";
        return 0;
    }
    

    Was die Bits angeht: Suchmasken und Flags können dir helfen, aber so, wie ich das sehe, werden sie nicht benötigt.



  • Glühbirne schrieb:

    Was die Bits angeht: Suchmasken und Flags können dir helfen, aber so, wie ich das sehe, werden sie nicht benötigt.

    Dann weißt du nicht, was Base64 ist.



  • Bashar schrieb:

    Glühbirne schrieb:

    Was die Bits angeht: Suchmasken und Flags können dir helfen, aber so, wie ich das sehe, werden sie nicht benötigt.

    Dann weißt du nicht, was Base64 ist.

    Tschuldigung, habe nicht gelesen, dass er einen Codierer schreiben will, ich dachte eher, er wollte einen Hex-Editor schreiben.

    Aber trotzdem, der Umgang mit den Operatoren ist leicht erlernt, man muss nur das Konzept verstehen.



  • verzweilter anfänger schrieb:

    Es gibt die Funktion .open aus dem fstream-header nicht?

    ifstream is;
    is.open("test.jpg" ios::binary);
    //tu was mit den Daten
    is.close();
    

    Diese Zeilen können nicht kompiliert werden?

    Wie 314.... schon sagte, es gibt diese Funktionen schon. Ich persönlich vermeide sie aber auch und lege lieber immer ein neues ifstream-Objekt an und geb dem Konstruktor die nötigen Daten mit. Denn wenn du close() aufrufst und danach wieder open(), werden die Fehlerbits nicht gelöscht, musst du dann von Hand machen und da man das gern vergisst, nutze ich lieber immer neue Objekte. Wenn ich mehrere Objekte hintereinander benötige bzw mehrer Dateien öffnen muss, geschieht das ja meist eh in einer Schleife, da ist es ja dann kein Problem, da Objekt immer neu zu erstellen, auch wenn das vielleicht bei größeren Mengen ein bisschen langsamer ist.

    Lg freeG



  • Glühbirne schrieb:

    Aber trotzdem, der Umgang mit den Operatoren ist leicht erlernt, man muss nur das Konzept verstehen.

    Aber immer noch schwerer als das Einlesen der Datei. Weshalb ich gar nicht verstehe, wieso hier die eigentliche Frage ignoriert und auf der Art und Weise, in der der Stream geöffnet wird, herumgeritten wird. Zum Glück hat er nicht void main geschrieben ...



  • Bashar schrieb:

    Glühbirne schrieb:

    Aber trotzdem, der Umgang mit den Operatoren ist leicht erlernt, man muss nur das Konzept verstehen.

    Aber immer noch schwerer als das Einlesen der Datei. Weshalb ich gar nicht verstehe, wieso hier die eigentliche Frage ignoriert und auf der Art und Weise, in der der Stream geöffnet wird, herumgeritten wird. Zum Glück hat er nicht void main geschrieben ...

    Ich wollte dem TE das lediglich mitteilen, damit er versteht warum 341... sagte, open() und close() seien sch***e und warum ich es im Normalfall auch nicht nutze. Ich reite doch darauf nicht herum 😉

    Lg freeG



  • Bashar schrieb:

    Zum Glück hat er nicht void main geschrieben ...

    Im Gegensatz zu void main() werden in den Anfänger Tuts und Büchern die open() und die close() Funktion als einzige Funktion zum öffnen bzw. schließen von Dateien erklärt.

    Im Moment lese ich die Datei so ein.

    flesen.open("b:\\icon1.png", ios::binary);
    	while (!flesen.eof())
        {
            getline(flesen, strzeile);
            strtext += strzeile;
        }
    	flesen.close();
    

    Dann hab ich ja alle Zeichen der Datei. Wie bekomme ich aber jetzt die Bit-codierung der einzelnen Zeichen und kann diese in einem String oder Zahlenarray speichern?



  • Nur Text per getline() einlesen, binäre Daten bitte mit istream::read()

    Dann hast du alles gelesene in nem char array und kannst damit machen, was du magst.

    So könnte es in der Theorie funktionieren, habs halt nicht getestet:

    class BitReader
    {
    private:
      std::ifstream m_file;
      std::vector<char> m_data;
      size_t m_bytePos, m_bitPos;
    
    public:
      BitReader(std::string const& path)
        : m_file(path.c_str()), m_data(), m_bytePos(0), m_bitPos(0)
      {
        m_file.seekg (0, std::ios::end);
        size_t length = m_file.tellg();
        m_file.seekg (0, std::ios::beg);
    
        m_data.resize(length);
        m_file.read(&m_data[0], length); 
      }
    
      size_t getNumBits() const
      {
        return m_data.size() * 8;
      }
    
      char getNextBit()
      {
        if(m_bitPos < 8)
        {
          char bit = m_data[m_bytePos] & 1;
          m_data[m_bytePos] >>= 1;
          ++m_bitPos;
          return bit; 
        }
        else
        {
          if(++m_bytePos >= m_data.size())
            throw std::exception("Data exhausted.");
    
          m_bitPos = 0;
          return getNextBit();
        }
      }
    };
    


  • Danke für die Hilfe Ethon.

    Mit deinem Code kann ich leider (noch) nichts anfangen. Da ich mit der Idee der OOP nichts anfangen kann.

    Das Auslesen scheint nun zu funktionieren.
    Nur die Umwandlung in

    int
    

    scheitert noch.

    atoi()
    

    beklagt sich über falsche Datentypen und

    static_cast<int> (char)
    

    gibt mir viel zu hohe Werte.

    Mein aktueller Umwandlungscode:

    iarray[i] = static_cast<unsigned int> (cbuffer[i]);
    

    Hat jemand dazu eine Idee woran das liegen könnte?



  • Mit

    iarray[i] = static_cast<unsigned int> (cbuffer[i]);
    

    steht in iarray[i] der ASCII-Code des Zeichens (bei Zahlen 48-57).
    atoi funktioniert auch mit std::strings, schau dir mal die Memberfunktion c_str() an, die einen const char* liefert. Weitere Möglichkeiten der Konvertierung findest du in dem FAQ-Post.

    Edit: Ich sehe gerade, dass nur jeweils nur einen char nach int konvertieren möchtest. Nach Ansicht der ASCII-Tabelle wirst du festellen, dass die Zahlen 0-9 in einem Bereich liegen, d.h. du musst lediglich den ASCII-Wert von 0, also 48, subtrahieren und hast die entsprechende Zahl.



  • yahendrik schrieb:

    Mit

    iarray[i] = static_cast<unsigned int> (cbuffer[i]);
    

    steht in iarray[i] der ASCII-Code des Zeichens (bei Zahlen 48-57).

    Genau den will ich ja, weil ich den dann ins Binärsystem umwandeln und dann mit base64 codieren kann.

    yahendrik schrieb:

    Edit: Ich sehe gerade, dass nur jeweils nur einen char nach int konvertieren möchtest. Nach Ansicht der ASCII-Tabelle wirst du festellen, dass die Zahlen 0-9 in einem Bereich liegen, d.h. du musst lediglich den ASCII-Wert von 0, also 48, subtrahieren und hast die entsprechende Zahl.

    Ich will auch immer nur ein Zeichen konvertieren, da ja jeder char aus genau einem Byte besteht.

    Aber wenn ich bei

    iarray[i] = static_cast<unsigned int> (cbuffer[i]);
    

    Werte im zehnstelligen Bereich bekomme stimmt doch was nicht, oder?



  • Eine Konvertierung nach int ist doch gar nicht nötig.

    Du liest die Datei so ein wie Ethon beschrieben hat, oder besser noch so:
    http://www.cplusplus.com/reference/iostream/istream/read/

    Danach wendest du deinen Base64-Algorithmus byteweise an.

    Edit:
    Beispiele findest du hier:
    http://www.google.de/search?q=base64+filetype:cpp



  • Ja, bloß muss ich dafür auf die Bits zugreifen können. Und wenn ich die Chars in Ints konvertiere kann ich diese ins Binärsystem umwandeln.


Log in to reply