int aus binärdatei



  • Hallo!

    Ich sitze im Moment an folgendem vereinfachtem Problem:
    Ich möchte aus einer 4 Byte großen Datei, einen int-Wert auslesen. Sagen wir es ist der Wert 0xf0a4bb71. In der Datei("binfile") steht damit als little-endian

    71 BB A4 F0
    

    Um das auszulesen habe ich folgende Funktion:

    unsigned int readInt()
    {
        fstream file;
        file.open("binfile", iostream::in|iostream::binary);
    
        unsigned char chrval[4];
    
        for(int i=0;i<4;i++)
        {
            file>>chrval[i];
        }
    
        unsigned int value = (chrval[3]<<24)|(chrval[2]<<16)|(chrval[1]<<8)|chrval[0];
    
        return value;
    }
    

    Das Funktioniert auch ganz gut... mit der gegebenen Zahl. Wenn ich eine Zahl nehme, in der das höchste Byte zwischen 10 und 13 liegt, kommt ein falsches Ergebnis heraus. Bei 0xcbb71 in der "binfile"

    71 BB 0C 00
    

    wird als Rückgabewert der Wert 0x7100bb71 gegeben.

    Kann mir das jemand erklären?

    Liebe Grüße
    Eike



  • Versuchs mal mit der read Methode des fstream statt mit >> . Letztere Funktion überspringt hier vermutlich Whitespace.



  • Ich vermute Du arbeitest mit einem x86 und in der Datei steht Littel Endian, da gibts nichts umzuwandeln.

    z.B.

    #include <fstream>
    using namespace std ;
    
    unsigned int readInt()
    {
        fstream file ;
        file.open("binfile", iostream::in|iostream::binary);
        unsigned int value ;
        file.read((char*)&value, sizeof(int)) ;
        return value  ;
    }
    int main()
    {
        ofstream file("binfile", iostream::out | iostream::binary) ;
        unsigned int wert = 0xcbb71 ; // 0xf0a4bb71 ;
        file.write((char*)&wert, sizeof(int)) ;
        file.close() ;
        unsigned int test = readInt() ;
        return 0 ;
    }
    

    mfg



  • Hallo Eike,

    Willkommen im C++-Forum.

    Bei dem Problem, welches Du gerade hast, empfehle ich immer, einen eigenen ibinstream zu benutzen. Du bist nicht der erste, der binär aus einer Datei liest 😉

    Die Anwendung sollte letzlich so aussehen:

    #include "ifbinstream.h" // siehe nächstes Listing
    #include <iostream>
    #include <cstdint> // std::int32_t
    
    int main()
    {
        using namespace std;
        ifbinstream file( "binfile" );
    
        std::int32_t i; // stellt sicher, dass genau 4 Byte gelesen werden!
        if( file >> i )
        {
            cout << "int " << i << " gelesen" << endl;
        }
        return 0;
    }
    

    Damit ist das Look&Feel genau wie beim std::ifstream, der auch nur ein std::istream ist. Letzterer ist für das Lesen von Formatierten Dateien gemacht, die 'vom Menschen lesbare' Zeichen enthalten. Daher ist die direkte Anwendung eines std::istreams hier nicht angesagt.

    Das "ifbinstream.h" ist ein Wrapper für den ibinstream zusammen mit einem std::filebuf

    // -- Datei ifbinstream.h
    #ifndef IFBINSTREAM_H_INCLUDED_
    #define IFBINSTREAM_H_INCLUDED_
    
    #include "ibinstream.h" // z.Beispiel: http://www.c-plusplus.net/forum/p1561419#1561419
    #include <fstream> // std::basic_filebuf
    
    class ifbinstream : public ibinstream
    {
    public:
        explicit ifbinstream( const char* filename, std::ios_base::openmode mode = std::ios_base::in )
            : ibinstream( &filebuf_ )
            , filebuf_()
        {
            if( !filebuf_.open( filename, mode | std::ios_base::in | std::ios_base::binary ) )
                setstate( std::ios_base::failbit );
        }
        bool is_open() const { return filebuf_.is_open(); }
    
    private:
        std::basic_filebuf< char > filebuf_;
    };
    #endif
    

    Eine Variante des ibinstream findest Du unter dem angegebenen Link. Falls Du vor einem Windows oder Linux OS sitzt, sollte der bereits so für Dich funktionieren.
    In Zeile 20 findest Du dort das eigentliche Lesen vom Streambuf (d.h in Deinem Fall aus der Datei).

    Gruß
    Werner



  • Oder man baut sich einfach einen eigenen Manipulator. 🤡



  • Finde C++-Streams bei binäroperationen ziemlich unangenehm.

    unsigned int readInt()
    {
        std::unique_ptr<FILE, decltype(&std::fclose)> file(std::fopen("binfile", "rb"), &std::fclose);
        if(!file)
            return 0;
    
        unsigned int result;
        return std::fread(&result, sizeof(result), 1, file) == sizeof(result) ? result : 0;
    }
    

    Oder am besten Generalisiert.

    typedef std::unique_ptr<FILE, decltype(&std::fclose)> File;
    
    template<typename T>
    T read(File& file, typename std::enable_if<std::is_pod<T>::value, void>::type* = 0)
    {
        T result;
        assert(std::fread(&result, sizeof(result), 1, file) == sizeof(result));
        return result;
    }
    
    template<typename T, class A = std::allocator<T>>
    std::vector<T, A> read(File& file, std::size_t count, typename std::enable_if<std::is_pod<T>::value, void>::type* = 0)
    {
        std::vector<T, A> result(count);
        assert(std::fread(result.data(), sizeof(T), count, file) == sizeof(T) * count);
        return result;
    }
    


  • Ethon schrieb:

    unsigned int readInt()
    {
        std::unique_ptr<FILE, decltype(&std::fclose)> file(std::fopen("binfile", "rb"), &std::fclose);
        if(!file)
            return 0;
    
        unsigned int result;
        return std::fread(&result, sizeof(result), 1, file) == sizeof(result) ? result : 0;
    }
    

    Seit wann darf man fclose mit Null aufrufen?



  • TyRoXx schrieb:

    Ethon schrieb:

    unsigned int readInt()
    {
        std::unique_ptr<FILE, decltype(&std::fclose)> file(std::fopen("binfile", "rb"), &std::fclose);
        if(!file)
            return 0;
    
        unsigned int result;
        return std::fread(&result, sizeof(result), 1, file) == sizeof(result) ? result : 0;
    }
    

    Seit wann darf man fclose mit Null aufrufen?

    Gute Qualität und frische Zutaten seit 1972.



  • Upps, darf man wirklich nicht. Komme etwas durcheinander, da ich mir für soetwas selbst etwas geschrieben habe, da mich immer schon das fehlende Copy bei der FILE/den Streams gestört hat, benutze die C-File API selten. Trotzdem angenehmer imho als mit den fetten Streams rumzuarbeiten, die dafür überhaupt nicht gedacht sind.

    Das Problem mit fclose wäre leicht zu lösen, würde aber immer hackier werden. Dadurch noch hässlicher als mit std::istream, also egal.


Anmelden zum Antworten