2016-03-23 23 views
2

ich zum Beispiel 4 Bytes aus der Datei Lesen Bits aus der Datei

ifstream r(filename , ios::binary | ios::in) 
uint_32 readHere; 
r.read((char*)&readHere, 4) 

mit

lesen Aber wie konnte ich lesen 4.5 Bytes = 4 Bytes und 4 Bits.

Was mir in den Sinn kam, ist

ifstream r(filename , ios::binary | std::in) 
uint_64t readHere; 
r.read((char*)&readHere, 5) // reading 5 bytes ; 

uint_64t tmp = readHere & 11111111 // extract 5th bytes 
tmp = tmp >> 4 // get first half of the bites 
readHere = ((readHere >> 8) << 8) | tmp  // remove 5th byte then add 4 bits 

aber im nicht sicher, wie die Hälfte der Byte shouldi zu nehmen, wenn die erste oder letzte 4. Gibt es eine bessere Art und Weise, wie es zurückzuholen?

+0

Es liegt ganz bei Ihnen zu entscheiden, welche Bits in einem Byte zuerst kommen. –

+0

Sie müssen 'readHere' als 'uint64_t' (oder etwas größer) deklarieren, um 5 Bytes darin zu speichern. – TriskalJM

+0

ja, vergaß es, danke ich werde es beheben. – Darlyn

Antwort

0

Die kleinste Einheit, die Sie in einer Datei lesen oder schreiben können, oder im Speicher ist ein Zeichen (ein Byte auf gemeinsamen Systemen (*)). Sie können länger Element-Byte-weise durchsuchen, und hier ist effektiv Endianess wichtig.

uint32_t u = 0xaabbccdd; 
char *p = static_cast<char *>(&u); 
char c = p[0]; // c is 0xdd on a little endian system and 0xaa on a big endian one 

Aber sobald Sie sind innerhalb ein Byte alles, was Sie tun können bitweise ands zu verwenden ist und verschiebt die niederwertigen oder höherwertigen Bits zu extrahieren. Es gibt hier keine Endianness mehr, außer wenn Sie entscheiden, eine Konvention zu verwenden.

BTW, wenn Sie lesen auf einer Netzwerkschnittstelle oder sogar auf einer seriellen Leitung, wo Bits einzeln übertragen werden, erhalten Sie ein ganzes Byte zu einer Zeit, und es gibt keine Möglichkeit, nur 4 Bits auf einem lesen und 4 zu lesen andere beim nächsten.

(*) ältere Systeme (CDC in den 80er Jahren) verwendet 6bits pro Charakter haben - aber C++ noch nicht existierte zu dieser Zeit und ich bin nicht sicher, ob C-Compiler gab es

0

Es ist immer noch nicht klar, ob diese ist ein Dateiformat, das Sie steuern, oder wenn es etwas anderes ist. Wie auch immer, lassen Sie uns annehmen, dass Sie einige Integer-Datentyp haben, der einen 36-Bit-Wert ohne Vorzeichen halten kann:

typedef uint64_t u36; 

Nun, unabhängig davon, ob Ihr System verwendet Big-Endian oder Little-Endian, können Sie den Wert auf einen Schreib Binärstrom in einer vorhersagbaren Reihenfolge, indem Sie sie ein Byte nach dem anderen tun. Lassen Sie uns Big-Endian verwenden, weil es etwas einfacher ist, sich die zusammengesetzten Bits vorzustellen, um einen Wert zu erzeugen.

Sie können nur naive Verschiebung und Maskierung in einen kleinen Puffer verwenden. Das einzige, was zu entscheiden ist, wo das Halbbyte abgeschnitten wird. Aber wenn Sie dem Muster folgen, bei dem jeder Wert um weitere 8 Bits verschoben wird, dann fällt der Rest natürlich in die höhere Ordnung.

ostream & write_u36(ostream & s, u36 val) 
{ 
    char bytes[5] = { 
     (val >> 28) & 0xff, 
     (val >> 20) & 0xff, 
     (val >> 12) & 0xff, 
     (val >> 4) & 0xff, 
     (val << 4) & 0xf0 
    }; 
    return s.write(bytes, 5); 
} 

Aber das ist nicht, wie Sie tatsächlich eine Reihe dieser Zahlen schreiben würden. Sie müßten das 5. Byte abwarten, bis Sie fertig waren oder Sie könnten den nächsten Wert hinein packen. Oder Sie würden immer zwei Werte in einer Zeit schreiben:

ostream & write_u36_pair(ostream & s, u36 a, u36 b) 
{ 
    char bytes[9] = { 
     (a >> 28) & 0xff, 
     (a >> 20) & 0xff, 
     (a >> 12) & 0xff, 
     (a >> 4) & 0xff, 
     (a << 4) & 0xf0 | (b >> 32) & 0x0f, 
     (b >> 24) & 0xff, 
     (b >> 16) & 0xff, 
     (b >> 8) & 0xff, 
     b & 0xff 
    }; 
    return s.write(bytes, 9); 
} 

Und jetzt, könnte man sehen, wie man über Lesen Werte und deserialising sie wieder in ganzen Zahlen. Der einfachste Weg ist, zwei gleichzeitig zu lesen.

istream & read_u36_pair(istream & s, u36 & a, u36 & b) 
{ 
    char bytes[9]; 
    if(s.read(bytes, 9)) 
    { 
     a = (u36)bytes[0] << 28 
      | (u36)bytes[1] << 20 
      | (u36)bytes[2] << 12 
      | (u36)bytes[3] << 4 
      | (u36)bytes[4] >> 4; 

     b = ((u36)bytes[4] & 0x0f) << 32 
      | (u36)bytes[5] << 24 
      | (u36)bytes[6] << 16 
      | (u36)bytes[7] << 8 
      | (u36)bytes[8]; 
    } 
    return s; 
} 

Wenn man ihnen einen nach dem anderen lesen wollte, dann würden Sie den Überblick über einigen Zustand zu halten, müssen so wußte man, wie viele Bytes (entweder 5 oder 4) zu lesen, und die Operationen verschieben anzuwenden.Etwas naiv wie folgt aus:

struct u36deser { 
    char bytes[5]; 
    int which = 0; 
}; 

istream & read_u36(istream & s, u36deser & state, u36 & val) 
{ 
    if(state.which == 0 && s.read(state.bytes, 5)) 
    { 
     val = (u36)state.bytes[0] << 28 
      | (u36)state.bytes[1] << 20 
      | (u36)state.bytes[2] << 12 
      | (u36)state.bytes[3] << 4 
      | (u36)state.bytes[4] >> 4; 
     state.which = 1; 
    } 
    else if(state.which == 1 && s.read(state.bytes, 4)) 
    { 
     val = ((u36)state.bytes[4] & 0x0f) << 32 // byte left over from previous call 
      | (u36)state.bytes[0] << 24 
      | (u36)state.bytes[1] << 16 
      | (u36)state.bytes[2] << 8 
      | (u36)state.bytes[3]; 
     state.which = 0; 
    } 
    return s; 
} 

All dies ist rein hypothetisch, was der Punkt Ihrer Frage ohnehin zu sein scheint. Es gibt viele andere Möglichkeiten, Bits zu serialisieren, und einige von ihnen sind überhaupt nicht offensichtlich.