文章目录
- 基本原理
 - 调用
 
基本原理
bz2和zlib的功能是基本一致的,只是算法不同。zlib模块此前已经总结了:zlib模块详解
bz2模块用到的压缩算法是bzip2算法,其核心是BW变换和MTF变换,当然最后少不了霍夫曼编码。
BWT,即Burrows–Wheeler变换,其基本思路是对输入序列进行重新排布,使得相同的值尽可能地聚集在一起,例如ABABC在经过BWT之后变成AABBC,其过程也非常有趣:对于长度为N的字串,将最后一位字符挪到最前,在进行N次之后会得到一个
    
     
      
       
        N
       
       
        ×
       
       
        N
       
      
      
       N\times N
      
     
    N×N的矩阵,随便列举一个数串abfacadabea,
test = "abfacadabea"
mat = []
for i in range(len(test)):
   mat.append(test)
   test = test[-1] + test[:-1]
pprint(mat)
'''
['abfacadabea',
 'aabfacadabe',
 'eaabfacadab',
 'beaabfacada',
 'abeaabfacad',
 'dabeaabfaca',
 'adabeaabfac',
 'cadabeaabfa',
 'acadabeaabf',
 'facadabeaab',
 'bfacadabeaa']
'''
 
然后对这个矩阵按列进行字典排序,就会得到
mat.sort()
>>> pprint(mat)
'''
['aabfacadabe',
 'abeaabfacad',
 'abfacadabea',
 'acadabeaabf',
 'adabeaabfac',
 'beaabfacada',
 'bfacadabeaa',
 'cadabeaabfa',
 'dabeaabfaca',
 'eaabfacadab',
 'facadabeaab']
'''
 
其最右端的edafcaaaabb便是经过BWT之后的字符串。和原字符串相比,显然比较规整。
BWT的逆变换则更加巧妙,将输出字符串写成一列,记作
    
     
      
       
        
         s
        
        
         0
        
       
      
      
       s_0
      
     
    s0,则对
    
     
      
       
        
         s
        
        
         0
        
       
      
      
       s_0
      
     
    s0进行排序,得到
    
     
      
       
        
         s
        
        
         1
        
       
      
      
       s_1
      
     
    s1;然后将二者并列放置,记作
    
     
      
       
        
         s
        
        
         0
        
       
       
        
         s
        
        
         1
        
       
      
      
       s_0s_1
      
     
    s0s1,在对
    
     
      
       
        
         s
        
        
         0
        
       
       
        
         s
        
        
         1
        
       
      
      
       s_0s_1
      
     
    s0s1进行字典排序,如此循环下去,一直得到
    
     
      
       
        
         s
        
        
         0
        
       
       
        
         s
        
        
         1
        
       
       
        .
       
       
        .
       
       
        .
       
       
        
         s
        
        
         N
        
       
      
      
       s_0s_1...s_N
      
     
    s0s1...sN为止,最终得到的字符矩阵,就是经过排序的mat。
由于这两个函数比较容易写,所以这里就将二者实现一下。
def bwt(s):
    mat = []
    mat = [s[-i:]+s[:-i] for i in range(len(s))]
    mat.sort()
    return ''.join([m[-1] for m in mat])
 
测试一下
>>> s
'abfacadabea'
>>> bwt(s)
'edafcaaaabb'   #这个值与刚刚得到的值是一样的
 
下面写逆变换
def anti_bwt(s):
    mat = [i for i in s]
    for _ in range(len(s)-1):
        mat.sort()
        mat = [i+m for i,m in zip(s,mat)]
    return mat
 
测试一下
>>> mat = anti_bwt(bwt(s))
>>> mat
['eaabfacadab', 'dabeaabfaca', 'aabfacadabe', 'facadabeaab', 'cadabeaabfa', 'abeaabfacad', 'abfacadabea', 'acadabeaabf', 'adabeaabfac', 'beaabfacada', 'bfacadabeaa']
>>> pprint(mat)
['eaabfacadab',
 'dabeaabfaca',
 'aabfacadabe',
 'facadabeaab',
 'cadabeaabfa',
 'abeaabfacad',
 'abfacadabea',
 'acadabeaabf',
 'adabeaabfac',
 'beaabfacada',
 'bfacadabeaa']
 
可见这个mat果然就是之前那个排好序的mat,由于这里每一样都是原始序列的拆分,一比对就能得到原始字符串。
调用
稍微讲解一下原理之后,可以先调用一下bz2模块中最关键的两个函数compress和decompress。
import bz2
import sys
ori = 'ifyoumissthetrainimonyouwillknowthatiamgone'*10
bOri = ori.encode()
sys.getsizeof(bOri) # 463
c = bz2.compress(bOri)
sys.getsizeof(c)    # 132
 
未采取压缩时,占内存463;压缩之后剩下132。
除了压缩和解压缩函数之外,bz2还提供了直接与文件交互的open,其封装为
bz2.open(filename, mode='rb', compresslevel=9, encoding=None, errors=None, newline=None)¶
 
其中compresslevel为压缩级别,从1到9,越大压缩率越高。
bz2模块提供了方便的文件交互函数open,有了这个就可以直接将数据另存为压缩文件了
>>> with bz2.open('test.bz2', 'w') as f:
...   f.write(ori.encode())
...
430
 
而且这个压缩文件可以直接用解压软件打开

既然能读,那自然能写
>>> with bz2.open('test.bz2', 'r') as f:
...   print(f.read())
...
b'ifyoumissthetrainimonyouwillknowthatiamgoneifyoumissthetrainimonyouwillknowthatiamgoneifyoumissthetrainimonyouwillknowthatiamgoneifyoumissthetrainimonyouwillknowthatiamgoneifyoumissthetrainimonyouwillknowthatiamgoneifyoumissthetrainimonyouwillknowthatiamgoneifyoumissthetrainimonyouwillknowthatiamgoneifyoumissthetrainimonyouwillknowthatiamgoneifyoumissthetrainimonyouwillknowthatiamgoneifyoumissthetrainimonyouwillknowthatiamgone'
                

















![[极客大挑战 2019]Havefun1、EasySQL(BUUCTF)](https://img-blog.csdnimg.cn/4c391d7e82fc404a8c6fa074f9c9e3b0.png)