CUBE SUGAR CONTAINER

技術系のこと書きます。

Python: gzip モジュールを使ってデータを圧縮・解凍する

今回は Python の標準ライブラリの gzip モジュールの使い方について。 上手く使えば Python から大きなデータを扱うときにディスクの節約になるかな。

使った環境は次の通り。

$ sw_vers 
ProductName:    Mac OS X
ProductVersion: 10.13.5
BuildVersion:   17F77
$ python -V
Python 3.6.5

まずは Python の REPL を起動しておく。

$ python

基本的な使い方

gzip モジュールの基本的な使い方としては、組み込み関数の open() っぽい使い勝手の gzip.open() 関数を使う。 この関数を通して得られたファイルライクオブジェクトに書き込むと、自動的に書き込んだデータが GZip で圧縮される。

試しに、実際にデータを書き込んでみよう。

>>> import gzip
>>> with gzip.open('example.txt.gz', mode='wt') as fp:
...     fp.write('Hello, World!\n')
... 
14

注意点としては、テキストデータ (ユニコード文字列) を扱うときは mode 引数に t を明示的に指定しなきゃいけない。 これは gzip.open() 関数がデフォルトではバイナリデータを扱うように作られているため。 明示的に t を指定しないとバイナリモードになる。 Python 3 における組み込みの open() 関数はテキストモードがデフォルトなので、ここは気をつける必要がある。

別のターミナルからファイルを確認すると、ちゃんと GZip 圧縮されたファイルができている。

$ file example.txt.gz           
example.txt.gz: gzip compressed data, was "example.txt", last modified: Wed Aug  1 13:23:58 2018, max compression

gzcat コマンドで内容を確認すると、ちゃんと書き込んだ内容が見える。

$ gzcat example.txt.gz 
Hello, World!

元の Python インタプリタに戻って、今度は読み込みをしてみよう。

>>> with gzip.open('example.txt.gz', mode='rt') as fp:
...     fp.read()
... 
'Hello, World!\n'

ちゃんと元の文字列が解凍できた。

gzip コマンドで圧縮したファイルからデータを読み出してみる

続いては Python 以外のアーカイバを使って圧縮したファイルを解凍できるか試してみよう。

gzip コマンドを使って圧縮したファイルを用意しておく。

$ echo "Hello, GZip" > greet.txt
$ gzip greet.txt
$ file greet.txt.gz  
greet.txt.gz: gzip compressed data, was "greet.txt", last modified: Wed Aug  1 13:27:00 2018, from Unix

先ほどと同じようにファイルからデータを読み込んでみよう。

>>> with gzip.open('greet.txt.gz', mode='rt') as fp:
...     fp.read()
... 
'Hello, GZip\n'

ちゃんと読み出せた。

ただし、公式ドキュメントを読むとサポートしていない形式もあるようだ。

13.2. gzip — gzip ファイルのサポート — Python 3.6.5 ドキュメント

バイナリデータを扱ってみる

登場機会として多そうなのは pickle モジュールとの組み合わせかな。 これも試してみよう。

pickle モジュールについては以下の記事で取り扱った。

blog.amedama.jp

以下の辞書データを GZip ファイルとして保存したい。

>>> d = {'message': 'Hello, World!'}

そこで、まずは pickle モジュールを使って、上記をバイト列に変換する。

>>> import pickle
>>> data = pickle.dumps(d)

こんな感じになった。

>>> data
b'\x80\x03}q\x00X\x07\x00\x00\x00messageq\x01X\r\x00\x00\x00Hello, World!q\x02s.'

上記のバイト列を gzip モジュール経由でファイルに書き込む。

>>> with gzip.open('dict.pickle.gz', mode='wb') as fp:
...     fp.write(data)
... 
41

別のターミナルから確認すると、ちゃんと GZip ファイルができている。

$ file dict.pickle.gz 
dict.pickle.gz: gzip compressed data, was "dict.pickle", last modified: Wed Aug  1 13:28:15 2018, max compression

書き込みはできたので、今度は読み込みを。

>>> with gzip.open('dict.pickle.gz', mode='rb') as fp:
...     data = fp.read()
... 
>>> data
b'\x80\x03}q\x00X\x07\x00\x00\x00messageq\x01X\r\x00\x00\x00Hello, World!q\x02s.'

さっきと同じバイト列が得られた。

pickle モジュールに読み込ませると、ちゃんと辞書データが元に戻せた。

>>> pickle.loads(data)
{'message': 'Hello, World!'}

いじょう。