2016-05-13 86 views
2

因此,文件系統處理字節,但我正在尋求以位爲單位讀/寫數據到文件。將位作爲位寫入文件

我有一個大約850mb的文件,目標是讓它小於100mb。我使用delta + huffman編碼來生成二進制的「代碼表」。當你添加所有的「位」(也就是文件中的0和1的總數)時,你會得到大約781,000,000個「比特」,因此理論上我應該能夠將它們存儲在大約90mb左右。這是我遇到問題的地方。

基於我看到其他的答案圍繞左右,這是我已經得到最接近:

with open(r'encoded_file.bin', 'wb') as f: 
    for val in filedict: 
      int_val = int(val[::-1], base=2) 
      bin_array = struct.pack('i', int_value) 
      f.write(bin_array) 

val沿着每個迭代傳遞是要寫入的二進制文件。這些沒有固定的長度,範圍從最普通的10到最長的111011001111001100。代碼長度爲5位,其中的平均值爲。上面的代碼生成一個大約600mb的文件,仍然離開目標。

目前我正在使用Python 2.7,如果我絕對必須,我可以到Python 3.x。 Python甚至可能嗎?像C或C++這樣的語言可以更簡單嗎?

+0

牢記,一個文件必須包含字節的整數(所以你不能真正寫一個文件只需2或18位)這不是直接**,而是可以用一些中間緩衝區來完成。 –

+0

那麼創建8位緩衝區然後經過一些寫入過程?填充最後一個或那個效果? – amza

+0

值是否已經是二進制格式,您可以將它們連接在一起並稍後將它們明確分開?或者你是否需要編碼額外的數據來表明邊界? –

回答

2

注意:因爲bytes對象只是在Python 2中的str的別名,所以我無法找到(體面的)寫下面兩種版本的方式,而不使用if USING_VS_3

作爲最小的接口從比特串去,可以寫,你可以使用類似這樣的文件的字節:

def _gen_parts(bits): 
    for start in range(0,len(bits),8): 
     b = int(bits[start:start+8], base=2) 
     if USING_VS_3: 
      yield b #bytes takes an iterator of ints 
     else: 
      yield chr(b) 

def bits_to_bytes(bits): # -> (bytes, "leftover") 
    split_i = -(len(bits)%8) 
    byte_gen = _gen_parts(bits[:split_i]) 
    if USING_VS_3: 
     whole = bytes(byte_gen) 
    else: 
     whole = "".join(byte_gen) 
    return whole, bits[split_i:] 

所以給人像'111011001111001100' to bits_to_bytes`二進制數據的字符串返回一個2字節元組(寫入文件的字節數據)和(留下位)。

那麼簡單,未優化的文件接口來處理部分字節的緩衝區可能是這樣的:

class Bit_writer: 
    def __init__(self,file): 
     self.file = file 
     self.buffer = "" 

    def write(self,bits): 
     byte_data, self.buffer = bits_to_bytes(self.buffer + bits) 
     self.file.write(byte_data) 

    def close(self): 
     #you may want to handle the padding differently? 
     byte_data,_ = bits_to_bytes("{0.buffer:0<8}".format(self)) 
     self.file.write(byte_data) 
     self.file.close() 

    def __enter__(self): # This will let you use a 'with' block 
     return self 
    def __exit__(self,*unused): 
     self.file.close()