2016-03-23 96 views
2

可以閱讀例如,從文件的4個字節使用讀取比特從文件

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

卻怎麼我讀4.5字節= 4字節和4位。

什麼來到我的腦海裏是

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 

但林不知道如果第一個或最後4 有沒有一些更好的方法如何檢索如何shouldi採取半字節,?

+0

完全由您來決定一個字節中的哪些位首先出現。 –

+0

你將需要聲明'readHere'爲'uint64_t'(或更大的東西),以便在其中存儲5個字節。 – TriskalJM

+0

是的,忘了它,謝謝我會修復它。 – Darlyn

回答

0

可以讀取或寫入的最小單位是文件或內存中的字符是char(常見系統(*)上的字節)。您可以按字節順序瀏覽更長的元素,並且這裏有效的字節順序很重要。

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 

但只要你是一個字節所有你能做的就是用按位ANDS,並轉移到提取低位或高位。除非決定使用一個約定,否則這裏不再有排列順序。

順便說一句,如果你在一個網絡接口上讀取數據,或者甚至在一個串行線上單獨傳輸數據位,你一次只能得到一個完整的字節,而且在一次讀取時只能讀取4個位,其他人在下一個。

(*)更早版本中使用的系統(CDC在80年代)有每個字符6比特 - 但是C++並沒有在那個時候存在,我不確定是否存在C編譯器有

0

它目前還不清楚這是否是您控制的的文件格式,或者是其他內容。無論如何,讓我們假設你有一個可以容納36位無符號值某個整數數據類型:

typedef uint64_t u36; 

現在,無論你的系統是否使用大端或小端,你可以寫值到二進制流以一個可預測的順序執行,一次執行一個字節。讓我們使用big-endian,因爲稍微更容易將組裝在一起的圖像繪製成價值。

你可以使用天真的移位和掩碼到一個小緩衝區。唯一要決定的是截斷半字節的地方。但是如果遵循將每個值移位另外8位的模式,則其餘部分自然會處於高位。

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); 
} 

但是,這不是你如何寫一堆這些數字。在完成之前,您必須暫停第5個字節,否則您可以將下一個值打包。或者,你總是在同一時間寫兩個值:

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); 
} 

所以現在,你可能會看到如何去閱讀值和deserialising它們放回整數。最簡單的方法是一次讀兩個。

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; 
} 

如果你想讀他們一次一個,你需要保留一些狀態的跟蹤,所以你知道如何讀取的字節數(5或4),以及移位操作應用。像這樣的天真幼稚:

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; 
} 

所有這些都是純粹的假設,無論如何,這似乎是你的問題的關鍵。還有很多其他的方式來串行化位,其中一些並不明顯。