Python3標準庫:zlib GNUzlib壓縮

来源:https://www.cnblogs.com/liuhui0308/archive/2020/03/27/12583668.html
-Advertisement-
Play Games

1. zlib GNUzlib壓縮 zlib模塊為GNU項目zlib壓縮庫中的很多函數提供了底層介面。 1.1 處理記憶體中的數據 使用zlib最簡單的方法要求把所有將要壓縮或解壓縮的數據存放在記憶體中。 import zlib import binascii original_data = b'Thi ...


1. zlib GNUzlib壓縮

zlib模塊為GNU項目zlib壓縮庫中的很多函數提供了底層介面。

1.1 處理記憶體中的數據

使用zlib最簡單的方法要求把所有將要壓縮或解壓縮的數據存放在記憶體中。

import zlib
import binascii

original_data = b'This is the original text.'
print('Original     :', len(original_data), original_data)

compressed = zlib.compress(original_data)
print('Compressed   :', len(compressed),
      binascii.hexlify(compressed))

decompressed = zlib.decompress(compressed)
print('Decompressed :', len(decompressed), decompressed)

compress()和decompress()函數都取一個位元組序列參數,並且返回一個位元組序列。

從前面的例子可以看到,少量數據的壓縮版本可能比未壓縮的版本還要大。具體的結果取決於輸入數據,不過觀察小數據集的壓縮開銷很有意思。 

import zlib

original_data = b'This is the original text.'

template = '{:>15}  {:>15}'
print(template.format('len(data)', 'len(compressed)'))
print(template.format('-' * 15, '-' * 15))

for i in range(5):
    data = original_data * i
    compressed = zlib.compress(data)
    highlight = '*' if len(data) < len(compressed) else ''
    print(template.format(len(data), len(compressed)), highlight)

輸出中的*突出顯示了哪些行的壓縮數據比未壓縮版本占用的記憶體更多。

zlib支持不同的壓縮級別,允許在計算成本和空間縮減量之間有所平衡。預設壓縮級別zlib.Z_DEFAULT_COMPRESSION為-1,這對應一個硬編碼值,表示性能和壓縮結果之間的一個折中。當前這對應級別6。

import zlib

input_data = b'Some repeated text.\n' * 1024
template = '{:>5}  {:>5}'

print(template.format('Level', 'Size'))
print(template.format('-----', '----'))

for i in range(0, 10):
    data = zlib.compress(input_data, i)
    print(template.format(i, len(data)))

壓縮級別為0意味著根本沒有壓縮。級別9要求的計算最多,同時會生成最小的輸出。如下麵的例子,對於一個給定的輸入,可以多個壓縮級別得到的空間縮減量是一樣的。

1.2 增量壓縮與解壓縮

這種記憶體中的壓縮方法有一些缺點,主要是系統需要有足夠的記憶體,可以在記憶體中同時駐留未壓縮和壓縮版本,因此這種方法對於真實世界的用例並不實用。另一種方法是使用Compress和Decompress對象以增量方式處理數據,這樣就不需要將整個數據集都放在記憶體中。

import zlibimport binascii

compressor = zlib.compressobj(1)

with open('lorem.txt','rb') as input:
    while True:
        block = input.read(64)
        if not block:
            break
        compressed = compressor.compress(block)
        if compressed:
            print('Compressed: {}'.format(
                binascii.hexlify(compressed)))
        else:
            print('buffering...')
    remaining = compressor.flush()
    print('Flushed: {}'.format(binascii.hexlify(remaining)))

這個例子從一個純文本文件讀取小數據塊,並把這個數據集傳至compress()。壓縮器維護壓縮數據的一個記憶體緩衝區。由於壓縮演算法依賴於校驗和以及最小塊大小,所以壓縮器每次接收更多輸入時可能並沒有準備好返回數據。如果它沒有準備好一個完整的壓縮塊,那便會返回一個空位元組串。當所有

1.3 混合內容流

在壓縮和未壓縮數據混合在一起的情況下,還可以使用decompressobj()返回的Decompress類。

import zlib

lorem = open('lorem.txt','rb').read()
compressed = zlib.compress(lorem)
combined = compressed +lorem

decompressor = zlib.decompressobj()
decompressed = decompressor.decompress(combined)

decompressed_matches = decompressed == lorem
print('Decompressed matches lorem:',decompressed_matches)

unused_matches = decompressor.unused_data == lorem
print('Unused data matches lorem:',unused_matches)

解壓縮所有數據後,unused_data屬性會包含未用的所有數據。

1.4 校驗和

除了壓縮和解壓縮函數,zlib還包括兩個用於計算數據的校驗和的函數,分別是adler32()和crc32()。這兩個函數計算出的校驗和都不能認為是密碼安全的,它們只用於數據完整性驗證。

import zlib

data = open('lorem.txt','rb').read()

cksum = zlib.adler32(data)
print('Adler32: {:12d}'.format(cksum))
print('       : {:12d}'.format(zlib.adler32(data,cksum)))

cksum = zlib.crc32(data)
print('CRC-32: {:12d}'.format(cksum))
print('       : {:12d}'.format(zlib.crc32(data,cksum)))

這兩個函數取相同的參數,包括一個包含數據的位元組串和一個可選值,這個值可作為校驗和的起點。這些函數會返回一個32位有符號整數值,這個值可以作為一個新的起點參數再傳回給後續的調用,以生成一個動態變化的校驗和。

1.5 壓縮網路數據

下一個代碼清單中的伺服器使用流壓縮器來響應文件名請求,它將文件的一個壓縮版本寫至與客戶通信的套接字中。

import zlib
import logging
import socketserver
import binascii

BLOCK_SIZE = 64


class ZlibRequestHandler(socketserver.BaseRequestHandler):

    logger = logging.getLogger('Server')

    def handle(self):
        compressor = zlib.compressobj(1)

        # Find out what file the client wants
        filename = self.request.recv(1024).decode('utf-8')
        self.logger.debug('client asked for: %r', filename)

        # Send chunks of the file as they are compressed
        with open(filename, 'rb') as input:
            while True:
                block = input.read(BLOCK_SIZE)
                if not block:
                    break
                self.logger.debug('RAW %r', block)
                compressed = compressor.compress(block)
                if compressed:
                    self.logger.debug(
                        'SENDING %r',
                        binascii.hexlify(compressed))
                    self.request.send(compressed)
                else:
                    self.logger.debug('BUFFERING')

        # Send any data being buffered by the compressor
        remaining = compressor.flush()
        while remaining:
            to_send = remaining[:BLOCK_SIZE]
            remaining = remaining[BLOCK_SIZE:]
            self.logger.debug('FLUSHING %r',
                              binascii.hexlify(to_send))
            self.request.send(to_send)
        return


if __name__ == '__main__':
    import socket
    import threading
    from io import BytesIO

    logging.basicConfig(
        level=logging.DEBUG,
        format='%(name)s: %(message)s',
    )
    logger = logging.getLogger('Client')

    # Set up a server, running in a separate thread
    address = ('localhost', 0)  # let the kernel assign a port
    server = socketserver.TCPServer(address, ZlibRequestHandler)
    ip, port = server.server_address  # what port was assigned?

    t = threading.Thread(target=server.serve_forever)
    t.setDaemon(True)
    t.start()

    # Connect to the server as a client
    logger.info('Contacting server on %s:%s', ip, port)
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((ip, port))

    # Ask for a file
    requested_file = 'lorem.txt'
    logger.debug('sending filename: %r', requested_file)
    len_sent = s.send(requested_file.encode('utf-8'))

    # Receive a response
    buffer = BytesIO()
    decompressor = zlib.decompressobj()
    while True:
        response = s.recv(BLOCK_SIZE)
        if not response:
            break
        logger.debug('READ %r', binascii.hexlify(response))

        # Include any unconsumed data when
        # feeding the decompressor.
        to_decompress = decompressor.unconsumed_tail + response
        while to_decompress:
            decompressed = decompressor.decompress(to_decompress)
            if decompressed:
                logger.debug('DECOMPRESSED %r', decompressed)
                buffer.write(decompressed)
                # Look for unconsumed data due to buffer overflow
                to_decompress = decompressor.unconsumed_tail
            else:
                logger.debug('BUFFERING')
                to_decompress = None

    # deal with data reamining inside the decompressor buffer
    remainder = decompressor.flush()
    if remainder:
        logger.debug('FLUSHED %r', remainder)
        buffer.write(remainder)

    full_response = buffer.getvalue()
    lorem = open('lorem.txt', 'rb').read()
    logger.debug('response matches file contents: %s',
                 full_response == lorem)

    # Clean up
    s.close()
    server.socket.close()

我們人為的將這個代碼清單做了一些劃分,以展示緩衝行為,如果將數據傳遞到compress()或decompress(),但沒有得到完整的壓縮或未壓縮輸出塊,此時便會進行緩衝。

客戶連接到套接字,並請求一個文件。然後迴圈,接收壓縮數據塊。由於一個塊可能未包含足夠多的信息來完全解壓縮,所以之前接收的剩餘數據將與新數據結合,並且傳遞到解壓縮器。解壓縮數據時,會把它追加到一個緩衝區,處理迴圈結束時將與文件內容進行比較。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 目錄 . 一、基本概念 . 1、背景 . 2、簡介 . 3、特點 . 4、基礎模型 . 5、Apollo 的四個維度 . 6、本地緩存 . 7、客戶端設計 . 8、總體設計 . 9、可用性考慮 . 二、Apollo 配置中心創建項目與配置 . 1、登錄 Apollo . 2、修改與增加部門數據 . ...
  • 實現步驟 1.導包:import java.util.Scanner; 2.Scanner類的實例化:Scanner scan = new Scanner(System.in); 3.調用Scanner類的相關方法(next() nextInt())獲取指定類型的變數; 註意:在控制台,如果輸入的類 ...
  • 一、分類 順序結構:程式從上而下依次執行 分支結構:if-else if-else、switch-case 迴圈結構:while迴圈、for迴圈、do-while迴圈、增強for迴圈 二、具體說明 1.分支結構 1.1if分支結構 說明 1.else結構是可選的; 2.if-else結構可以嵌套使用 ...
  • 原文鏈接:http://www.yiidian.com/servlet/servlet how work.html 接下來我們有必要瞭解下Servlet的工作原理,這樣才能更好地理解Servlet。本文我們將以之前開發過的Servlet程式來講解Servlet的內部細節。 1 Servlet基本執行 ...
  • 1. 方法 註:class(類)是具有相同的屬性和方法的對象的集合。 2. 例子 (1)數據/集合類型 str(object=''); str(object=b'', encoding='utf-8', errors='strict') int(x, base=10) float(x=0) comp ...
  • 我用java爬蟲爬了一個圖片網站 最近想建立個網站,不想搞技術博客之類的網站了,因為像博客園還有CSDN這種足夠了。平時的問題也都是這些記錄一下就夠了。那搞個什麼網站好玩呢? 看到一個圖片網站還不錯,裡面好多圖片(當然有xxx圖片了....)哈哈,其實就是閑的,同時也介紹一下java爬蟲的相關用法把 ...
  • 目錄 一級緩存 二級緩存 自定義緩存 一級緩存 MyBatis 包含了一個非常強大的查詢緩存特性,它可以非常方便地配置和定製。MyBatis 3 中的緩存實現的很多改進都已經實現了,使得它更加強大而且易於配置。mybatis預設情況下只會開啟一級緩存,也就是局部的 session 會話緩存。 首先我 ...
  • 區別 1.使用範圍和規範不同 filter是servlet規範規定的,只能用在web程式中. 攔截器即可以用在web程式中, 也可以用於application, swing程式中, 是Spring容器內的, 是Spring框架支持的 2.觸發時機不同 順序: Filter Servlet Inter ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...