プロジェクト

全般

プロフィール

操作

第12章 データ圧縮、アーカイブと永続化

12.1 gzip 圧縮ファイルを扱う gzip

gzip形式のファイル圧縮・展開 (gzip, gunzip コマンドと同等)

  • gzip ファイルを圧縮、展開する

    関数名 解説 戻り値
    open(filename, mode='rb', compresslevel=9, encoding=None, errors=None, newline=None) gzip形式のファイルを開き、ファイルオブジェクトを返す
    読み込みモードなら既存のファイルを開き、書き込みモードならファイル作成する(*1)
    gzip.GzipFile
    compress(data, compresslevel=9, *, mtime=None) 指定されたデータを gzip 圧縮する
    データは bytes 型である必要がある
    bytes
    decompress(data) 指定された gzip 圧縮されたデータを展開し bytes オブジェクトを返す bytes
    • (*1) gzip 仕様は追記に対応しておらず、open() の mode に追記 (a 等) を指定しても、新規書き込みとして扱われる

      >>> import gzip
      >>> with gzip.open("sample.gz", "wt") as f:
      ...     f.write("適当な文字列。" * 10)
      ...
      70
      
      適当な文字列。適当な文字列。適当な文字列。適当な文字列。適当な文字列。適当な文字列。適当な文字列。適当な文字列。適当な文字列。適当な文字列。
      
      >>> with gzip.open("sample.gz", "wt") as f:
      ...     f.write("\n適当な文字列。" * 10)
      ...
      80
      
      
      適当な文字列。
      適当な文字列。
      適当な文字列。
      適当な文字列。
      適当な文字列。
      適当な文字列。
      適当な文字列。
      適当な文字列。
      適当な文字列。
      適当な文字列。
      
    • 圧縮、解凍

      >>> text = "適当な文字列。" * 10
      >>> text
      '適当な文字列。適当な文字列。適当な文字列。適当な文字列。適当な文字列。適当な文字列。適当な文字列。適当な文字列。適当な 文字列。適当な文字列。'
      >>> len(text)
      70
      >>> btext = text.encode("utf-8")    # bytes 型へ
      >>> len(btext)
      210
      >>> comp = gzip.compress(btext)     # 圧縮
      >>> len(comp)
      46
      >>> decomp = gzip.decompress(comp)  # 解凍
      >>> len(decomp)
      210
      >>> btext == decomp     # bytes 型で同値
      True
      >>> decomptext = decomp.decode("utf-8")
      >>> len(decomptext)
      70
      >>> decomptext
      '適当な文字列。適当な文字列。適当な文字列。適当な文字列。適当な文字列。適当な文字列。適当な文字列。適当な文字列。適当な 文字列。適当な文字列。'
      >>> decomptext == text  # str 型で同値
      True
      

12.2 ZIP ファイルを扱う zipfile

ZIP形式でアーカイブされたファイルを扱う

  • ZIP ファイルを操作する
    • class ZipFile(file, mode='r' compression=ZIP_STORED, allowZip64=True, compresslevel=None, *, strict_timstamps=True)

      • file 対象となる ZIP アーカイブ (ファイル名や path-like オブジェクト)
      • mode
        • r 読み込み、w 新規作成(既存を削除)、a 追記、x 新規作成(既存はエラー)
      • compression ZIP 圧縮方法
        • ZIP_DEFLATED zlib モジュール必要
        • ZIP_BZIP2 bz2 モジュール必要
        • ZIP_LZMA lzma モジュール必要
      • allowZip64 True の場合、4GiB 以上の ZIP ファイル作成に ZIP64 形式にする
      • compresslevel 圧縮レベル
        • ZIP_DEFLATED : 0-9
        • ZIP_BZIP2 : 1-9
      • strict_timestamps False の場合、1980 年より前のタイムスタンプを 1980-01-01 に、2108年以降のタイムスタンプを 2107-12-31 に設定する
      • 戻り値 zipfile.ZipFile
    • 関数 is_zipfile(filename)

      • filename ファイル名、path-like オブジェクト
      • 戻り値 bool
    • ZipFile オブジェクトのメソッド

      メソッド名 解説 戻り値
      infolist() ZipInfo のリストを返す list
      namelist() アーカイブされているファイル名のリストを返す list
      getinfo(name) 指定されたファイルの ZipInfo を返す ZipInfo
      open(name, mode='r', pwd=None, *, force_zip64=None) 指定したファイルを開く (コンテキストマネージャー) ZipExtFile
      extract(member, path=None, pwd=None) 指定 (ファイル名、ZipInfo) されたファイルを展開し、パスを返す str
      extractall(path=None, members=None, pwd=None) 全ファイルを展開する None
      read(name, pwd=None) 指定されたファイルの中身を返す bytes
      write(filename, arcname=None, compress_type=None) 指定したファイルを ZIP ファイルへ書き込む
      arcname を指定の場合、その名前でアーカイブされる
      None
      writestr(zinfo_or_arcname, data, compress_type=None, compresslevel=None) 指定したファイル名に対してデータ (str または bytes) を書き込む None
      close() ZipFile を閉じる None
      • write() writestr() の引数 compress_type の値は、ZipFile のパラメータ compression と同じ選択肢で、メソッドでの指定が優先される
    • ZipInfo クラスは、ZIP ファイル内の1ファイル (ディレクトリ含む) の情報

      属性名、メソッド名 解説 戻り値
      filename ファイル名 str
      date_time 最終更新日時 (6要素タプル) tuple
      compress_size 圧縮後サイズ int
      file_size 圧縮前サイズ int
      is_dir() ディレクトリの場合、True bool
    • ZipExtFile クラスは、読み取り専用の file-like オブジェクト

      メソッド名 解説 戻り値
      read(size=-1, /) 指定バイト数まで読み出す bytes
      readline(size=-1, /) 指定バイト数、行末までの小さい方まで読み出す bytes
      readlines(hint=-1, /) 指定行数まで読み出し、行のリストを返す
      ※通常、行処理には for line in file: を使用する
      list
      seek(offset, whence=os.SEEK_SET, /) (略) int
      tell() (略) int
      >>> import zipfile
      >>> zipfile.is_zipfile('python-3.9.4-docs-text.zip')  # ZIPファイルかチェック
      True
      >>> zip = zipfile.ZipFile('python-3.9.4-docs-text.zip')  # ZIPファイルを開く
      >>> len(zip.namelist())  # ファイル数を確認
      505
      >>> zip.namelist()[:2]  # 先頭2件のファイル名を取得
      ['python-3.9.4-docs-text/', 'python-3.9.4-docs-text/contents.txt']
      >>> with zip.open('python-3.9.4-docs-text/contents.txt') as f:  # ファイルを開く
      ...     contents = f.read()
      ...
      >>> contents[:40]  # 先頭の40文字を確認
      b'Python Documentation contents\n**********'
      
      >>> for name in zip.namelist():  # zipfileモジュールのドキュメントを探す
      ...     if 'zipfile' in name:
      ...         zipfile_doc = name
      ...         break
      ...
      >>> zipfile_doc  # ファイル名を確認
      'python-3.9.4-docs-text/library/zipfile.txt'
      >>> zipfile_info = zip.getinfo(zipfile_doc)  # ZipInfoを取得
      >>> zipfile_info.date_time  # 最終更新日を確認
      (2021, 4, 10, 12, 7, 54)
      >>> zip.extract(zipfile_info)  # zipfileのマニュアルを展開する
      '/Users/takanori/python-3.9.4-docs-text/library/zipfile.txt'
      
      >>> with zipfile.ZipFile('example.zip', mode='w', zipfile.ZIP_DEFLATED) as wzip:
      ...     wzip.write('spam.txt')  # ファイルを追加する
      ...     wzip.write('ham.txt', 'hamham.txt')  # ファイルを別名で追加する
      ...     wzip.writestr('eggs.txt', 'たまご')  # ファイル名を指定しテキストを直接書き込む
      ...     wzip.namelist()  # ファイルを確認する
      ...
      ['spam.txt', 'hamham.txt', 'eggs.txt']
      >>> zipfile.is_zipfile('example.zip')  # 正しいZIPファイルかを確認
      True
      

12.3 tar ファイルを扱う tarfile

gzip, bz2, lzma 形式で圧縮されたものを含む、tar 形式アーカイブを読み書きする

  • tar ファイルを操作する
    • 関数 open(name=None, mode='r', fileobj=None, bufsize=20240, **kwargs)

      • name tar ファイルのファイル名
      • mode モード指定 r w
        • 圧縮形式を指定する場合は r:gz w:xz 等 (非圧縮指定は w: 等)
        • 読み込み時は r だけでも、ファイル名拡張子から圧縮形式が自動判定される
        • 圧縮ファイルは追記モードが使用できない (a a: のみ)
      • fileobj tar ファイルのファイルオブジェクト
      • bufsize ブロックサイズ (デフォルトでよい)
      • 戻り値 tarfile.TarFile
    • 関数 is_tarfile(name)

      • name ファイル名、または file-like オブジェクト
      • 戻り値 (bool) 指定ファイルが tar 形式アーカイブなら True
    • TarFile オブジェクトのメソッド

      メソッド名 解説 戻り値
      getnames() tar ファイル内にアーカイブされているファイル名リスト list
      getmember(name) 指定ファイル名の TarInfo を返す TarInfo
      getmembers() tar ファイル内にアーカイブされている全ファイルの TarFile のリストを返す list
      extract(member, path="", set_attrs=True, *, numeric_owner=False) 指定ファイルを指定場所へ展開
      member:ファイル名またはTarInfo
      None
      extractall(path="", set_attrs=True, *, numeric_owner=False) 全ファイルを指定場所へ展開 None
      extractfile(member) 指定ファイルを開き、ファイルオブジェクトを返す
      member:ファイル名またはTarInfo
      ファイルオブジェクト
      add(name, arcname=None, recursive=True, exclude=None, *, filter=None) 指定ファイルを tar ファイルのアーカイブへ追加する
      arcnameを指定するとそのファイル名で追加
      ディレクトリ指定では再帰追加可能
      ?
      close() None
      >>> import tarfile
      >>> with tarfile.open("./testarchive.tar", "w:gz") as f:
      ...     f.add("./inArchive1.txt")
      ...
      >>> with tarfile.open("./testarchive.tar") as f:
      ...     f.getnames()
      ...     f.getmembers()
      ...
      ['./inArchive1.txt']
      [<TarInfo './inArchive1.txt' at 0x140b4104640>]
      >>> with tarfile.open("./testarchive.tar") as f:
      ...     with f.extractfile("./inArchive1.txt") as elem:
      ...         elem.read().decode("sjis")
      ...
      'アーカイブ内ファイル1'
      >>> with tarfile.open("./testarchive.tar") as f:
      ...     info = f.getmember("./inArchive1.txt")
      ...     info
      ...     print(f"{info.name=}, {info.size=}, {info.mtime=}, {info.mode=:o}")
      ...
      <TarInfo './inArchive1.txt' at 0x140b4104940>
      info.name='./inArchive1.txt', info.size=22, info.mtime=1753410842.0, info.mode=666
      >>> with tarfile.open("./testarchive.tar") as f:
      

12.4 Python オブジェクトをシリアライズする pickle

Python オブジェクトをファイル等に保存可能なバイト列に変換 (pickle 化 という)、復元 (非 pickle 化 という) する

  • JSON へのシリアライズ方法である json モジュールとの比較

    • JSON は文字列だが、pickle はバイナリ
    • JSON は他のプログラミング言語でも利用可能だが、pickle は Python 固有フォーマット
    • JSON は文字列、数値など一部のデータ型のみ扱うが、pickle は Python の様々なオブジェクトを扱える
  • Python オブジェクトのシリアライズとデシリアライズ

    関数名 解説 戻り値
    dump(obj, file, protocol=None, *, fix_imports=True, buffer_callback=None) オブジェクトをシリアライズしてファイルへ保存する None
    dumps(obj, protocol=None, *, fix_import=True, buffer_callback=None) オブジェクトをシリアライズしてバイト列を返す bytes
    load(file, *, fix_imports=True, encoding="ASCII", errors="strict", buffers=None) ファイルの中身をデシリアライズし、結果オブジェクトを返す object
    loads(data, /, *, fix_imports=True, encoding="ASCII", errors="strict", buffers=None) バイト列をデシリアライズし、結果オブジェクトを返す object

    dumps, loads (bytes でのやり取り) の例

    >>> import pickle
    >>> from datetime import datetime
    >>> now = datetime.now()
    >>> data = {"NOW-date": now}  # 値が datetime の辞書データ作成
    >>> type(data)
    <class 'dict'>
    >>> data
    {'NOW-date': datetime.datetime(2025, 7, 25, 16, 4, 0, 201811)}
    >>> serialized = pickle.dumps(data)  # シリアライズ
    >>> serialized
    b'\x80\x04\x958\x00\x00\x00\x00\x00\x00\x00}\x94\x8c\x08NOW-date\x94\x8c\x08datetime\x94\x8c\x08datetime\x94\x93\x94C\n\x07\xe9\x07\x19\x10\x04\x00\x03\x14S\x94\x85\x94R\x94s.'
    >>> desirialized = pickle.loads(serialized)  # デシリアライズ
    >>> type(desirialized)
    <class 'dict'>
    >>> desirialized  # 元のデータを復元できている
    {'NOW-date': datetime.datetime(2025, 7, 25, 16, 4, 0, 201811)}
    

    dump, load (ファイルでのやり取り) の例

    >>> data  # 対象データ
    {'NOW-date': datetime.datetime(2025, 7, 25, 16, 4, 0, 201811)}
    >>> with open("nowdate.pkl", "wb") as f:
    ...     pickle.dump(data, f)  # シリアライズしてファイルへ書き込み
    ...
    >>> with open("nowdate.pkl", "rb") as f:
    ...     obj = pickle.load(f)  # ファイル内容をデシリアライズ
    ...
    >>> obj  # 復元を確認
    {'NOW-date': datetime.datetime(2025, 7, 25, 16, 4, 0, 201811)}
    

    dump() で生成されたファイルの様子
    nowdata.jpg

    • ※ pickle 化にはプロトコルのバージョンが 0 から 5 まであり、新しいバージョンで pickle 化されたオブジェクトは古いバージョンで非 pickle 化できない (pickle.DEFAULT_PROTOCOL でデフォルト確認可能)

Tatsuya ISHIGAKI さんが5ヶ月前に更新 · 4件の履歴