[解決!Python]zipfileモジュールを使ってZIPファイルの読み込み/展開を行うには解決!Python

PythonにはZIPファイルを読み書きするためのzipfileモジュールが標準で付属している。これを使ってZIPファイルを展開したり、その内容を読み込んだりする方法を紹介する。

» 2023年12月05日 05時00分 公開
[かわさきしんじDeep Insider編集部]
「解決!Python」のインデックス

連載目次

from zipfile import ZipFile

# 基本型
zf = ZipFile('sample.zip'# ZIPファイルを読み込みモードで開く
f = zf.open('hogehoge.txt'# zfオブジェクトを使って、アーカイブの内部を操作
contents = f.read()
print(contents)  # b'foo\nbar\nbaz'
f.close()  # アーカイブから読み込んだファイルをクローズ
zf.close()  # ZipFileをクローズ

# with文を使用
with ZipFile('sample.zip') as zf:
    with zf.open('hogehoge.txt') as f:
        contents = f.read()
        print(contents)  # b'foo\nbar\nbaz'

# ZIPファイルの内容を表示
with ZipFile('sample.zip') as zf:
    zf.printdir()
# 出力結果:
#File Name                                             Modified             Size
#foo.txt                                        2023-11-30 10:27:14            7
#a/baz.txt                                      2023-11-30 10:27:14            9
#hogehoge.txt                                   2023-11-30 10:27:14           11

# ZIPファイルに含まれるメンバーのリストを取得
with ZipFile('sample.zip') as zf:
    name_list = zf.namelist()
    print(name_list)  # ['foo.txt', 'a/baz.txt', 'hogehoge.txt']

# ZIPファイルの展開
with ZipFile('sample.zip') as zf:
    zf.extractall()  # 全てのファイル/ディレクトリを展開

with ZipFile('sample.zip') as zf:
    zf.extractall(path='tmp'# カレントディレクトリのtmpディレクトリに展開

print(name_list[:2])  # ['foo.txt', 'a/baz.txt']

with ZipFile('sample.zip') as zf:
    zf.extractall(members=name_list[:2])  # 展開するファイルを指定

with ZipFile('sample_with_pwd.zip') as zf:
    zf.extractall(pwd=b'…………'# パスワードを指定(文字列ではなくbytes列)

# ファイルを指定して展開
print(name_list)  # ['foo.txt', 'a/baz.txt', 'hogehoge.txt']
with ZipFile('sample.zip') as zf:
    zf.extract('hogehoge.txt')

with ZipFile('sample.zip') as zf:
    zf.extract('hogehoge.txt', path='test'# 展開先を指定

with ZipFile('sample_with_pwd.zip') as zf:
    zf.extract('hogehoge.txt', pwd=b'…………'# パスワードを指定

# ZIPファイルに含まれる特定のファイルを読み込む
with ZipFile('sample.zip') as zf:
    with zf.open('hogehoge.txt') as f:
        for line in f:
            print(line)
            print(line.decode(encoding='UTF-8'))
# 出力結果:
#b'foo\n'
#foo
#
#b'bar\n'
#bar
#
#b'baz'
#baz

# ZIPファイル中のメンバーの情報を取得
with ZipFile('sample.zip') as zf:
    info_list = zf.infolist()
    for info in info_list:
        print(f'file: {info.filename}, date: {info.date_time}')
# 出力結果:
#file: foo.txt, date: (2023, 11, 30, 10, 27, 14)
#file: a/baz.txt, date: (2023, 11, 30, 10, 27, 14)
#file: hogehoge.txt, date: (2023, 11, 30, 10, 27, 14)

with ZipFile('sample.zip') as zf:
    info = zf.getinfo('hogehoge.txt'# 特定のファイルの情報を取得
    print(f'file: {info.filename}, size: {info.file_size}')
# 出力結果:
#file: hogehoge.txt, size: 11


ZIPファイルの読み込みとメンバーの取得/表示

 Pythonに標準で付属しているzipfileモジュールを使うと、ZIPファイルの展開や、そこに含まれているファイルの読み込みなどを簡単に行える。これにはzipfileモジュールのZipFileクラスを使用する。

 その基本型を以下に示す。なお、ここでは「zipfileモジュールを使ってZIPファイルに書き込みを行うには」で作成したZIPファイルをサンプルとして使用している。

from zipfile import ZipFile

# 基本型
zf = ZipFile('sample.zip'# ZIPファイルを読み込みモードで開く
f = zf.open('hogehoge.txt'# zfオブジェクトを使って、アーカイブの内部を操作
contents = f.read()
print(contents)  # b'foo\nbar\nbaz'
f.close()  # アーカイブから読み込んだファイルをクローズ
zf.close()  # ZipFileをクローズ


 この例ではまず読み込むZIPファイルの名前を指定して、ZipFileオブジェクトを作成している。次に、ZipFileオブジェクトを介して、ZIPファイルを操作する。上の例では、アーカイブ内の特定のファイル(hogehoge.txtファイル)をオープンして読み込み、その結果を表示している。しかし、そうではなく、ZIPファイルの全てのメンバーを展開したり、ZIPファイルに格納されているメンバーの情報を取得したりすることも可能だ。ZIPファイルの操作が終わったら、closeメソッドを呼び出してZIPファイルをクローズする(上の例では、アーカイブ内のファイルをオープンしているので、その前にそのファイルもクローズしている)。

 ZipFileオブジェクトはコンテキストマネジャーとしても機能する。そのため、上のコードは次のようにも書ける。

with ZipFile('sample.zip') as zf:
    with zf.open('hogehoge.txt') as f:
        contents = f.read()
        print(contents)  # b'foo\nbar\nbaz'


 以下ではこちらの書き方を採用してサンプルコードを紹介していこう。

ZIPファイルの内容を表示

 ZIPファイルにどんなメンバー(ファイル/ディレクトリ)が含まれているかを知るには、printdirメソッドが使える。これは、標準出力にファイル名や変更日時、ファイルサイズを表示するものだ。以下に使用例を示す。

with ZipFile('sample.zip') as zf:
    zf.printdir()
# 出力結果:
#File Name                                             Modified             Size
#foo.txt                                        2023-11-30 10:27:14            7
#a/baz.txt                                      2023-11-30 10:27:14            9
#hogehoge.txt                                   2023-11-30 10:27:14           11


 メンバーの一覧をリストとして取得するnamelistメソッドもある。

with ZipFile('sample.zip') as zf:
    name_list = zf.namelist()
    print(name_list)  # ['foo.txt', 'a/baz.txt', 'hogehoge.txt']


 この例の出力結果を見ると分かるように、namelistメソッドはメンバー名(文字列)を要素とするリストを返す。ZIPファイルのメンバーの情報を取得するメソッドは他にもあるが、それらについては後述する。

ZIPファイルの展開

 ZIPファイルを展開するには、以下の2つのメソッドを使える。

  • extractメソッド:指定したファイルを展開する
  • extractallメソッド:ZIPファイル内の全てのファイルを展開する

 アーカイブに含まれる全てのファイルを展開するなら、extractallメソッドを使うのが簡単だ。以下に例を示す。

with ZipFile('sample.zip') as zf:
    zf.extractall()  # 全てのファイル/ディレクトリを展開


 この例では、sample.zipファイルを表すZipFileオブジェクトを作成し、そのextractallメソッドを呼び出している。これにより、現在の作業ディレクトリの下にZIPファイルの内容が展開される。

 展開先を指定するにはextractallメソッドのpathパラメーターに展開先のディレクトリを指定する。以下に例を示す。

with ZipFile('sample.zip') as zf:
    zf.extractall(path='tmp'# カレントディレクトリのtmpディレクトリに展開


 「extractall」という名前ではあるが、展開したいファイルを指定することも可能だ。これにはmembersパラメーターに展開したいファイルを含むリストを指定する。

print(name_list[:2])  # ['foo.txt', 'a/baz.txt']

with ZipFile('sample.zip') as zf:
    zf.extractall(members=name_list[:2])  # 展開するファイルを指定


 この例では、先ほど、namelistメソッドで取得したファイル名一覧から先頭の2つのファイルをmembersパラメーターに指定している。このとき、存在しないファイルを指定すると例外が発生する。

 ZIPファイルにパスワードが設定されている場合にはpwdパラメーターにパスワードを指定する。pwdパラメーターに渡すのはbytes列である点にも注意しよう。以下に例を示す。

with ZipFile('sample_with_pwd.zip') as zf:
    zf.extractall(pwd=b'…………'# パスワードを指定(文字列ではなくbytes列)


 ファイルを指定して展開するにはextractメソッドを指定する。pathパラメーターやpwdパラメーターはextractallメソッドと同様なので、ここでは紹介は省略する。以下に例をまとめて示しておこう。

print(name_list)  # ['foo.txt', 'a/baz.txt', 'hogehoge.txt']
with ZipFile('sample.zip') as zf:
    zf.extract('hogehoge.txt')

with ZipFile('sample.zip') as zf:
    zf.extract('hogehoge.txt', path='test'# 展開先を指定

with ZipFile('sample_with_pwd.zip') as zf:
    zf.extract('hogehoge.txt', pwd=b'…………'# パスワードを指定


 なお、これらのメソッドでアーカイブを展開する際には注意点がある。それはアーカイブ内のメンバーの名前がフルパスのときには、それらはフルパスとしては扱われずに、現在の作業ディレクトリ以下に展開されるということだ(セキュリティ面を考慮して、このような振る舞いになっている。詳しくはドキュメントを参照されたい)。

ZIPファイルに含まれる特定のファイルを読み込む

 アーカイブに含まれる特定のファイルだけを読み出して、その内容に従って何かの処理をしたいということもあるだろう。そうしたときには、ZipFileオブジェクトのopenメソッドを使って、そのファイルをオープンし、通常のファイルと同様にreadメソッドなどを使ってその内容を読み込める。以下に例を示す(with文が二重になっている)。

with ZipFile('sample.zip') as zf:
    with zf.open('hogehoge.txt') as f:
        for line in f:
            print(line)
            print(line.decode(encoding='UTF-8'))
# 出力結果:
#b'foo\n'
#foo
#
#b'bar\n'
#bar
#
#b'baz'
#baz


 この例では、内側のwith文でアーカイブ内のhogehoge.txtファイルをオープンし、その内容をfor文を使って読み出して、表示している。2つのprint関数の出力結果を見ると分かるが、読み出した内容は文字列ではなくbytes列になっていることに注意しよう。オープンしたのがテキストファイルであっても、バイナリファイルとしてオープンされる。テキストファイルの内容を文字列として扱うのであれば、2つ目のprint関数呼び出しの中で行っているようにdecodeメソッドを呼び出す必要がある。

ZIPファイル中のメンバーの情報を取得

 アーカイブのメンバーの詳細な情報を得るには、 以下の2つのメソッドを使える。

  • infolistメソッド:アーカイブのメンバーの情報(ZipInfoオブジェクト)を要素とするリストを返す
  • getinfoメソッド:指定したメンバーの情報(ZipInfoオブジェクト)を返す

 以下に例を示す。

with ZipFile('sample.zip') as zf:
    info_list = zf.infolist()
    for info in info_list:
        print(f'file: {info.filename}, date: {info.date_time}')
# 出力結果:
#file: foo.txt, date: (2023, 11, 30, 10, 27, 14)
#file: a/baz.txt, date: (2023, 11, 30, 10, 27, 14)
#file: hogehoge.txt, date: (2023, 11, 30, 10, 27, 14)


 この例では、infolistメソッドを呼び出してサンプルのZIPファイルに含まれているファイルの情報を得て、それらからファイル名と最終更新日時を表示している。

with ZipFile('sample.zip') as zf:
    info = zf.getinfo('hogehoge.txt'# 特定のファイルの情報を取得
    print(f'file: {info.filename}, size: {info.file_size}')
# 出力結果:
#file: hogehoge.txt, size: 11


 この例では、getinfoメソッドを呼び出してZIPファイルに含まれているhogehoge.txtファイルの情報を取得して、そのファイル名とファイルサイズを表示している。

 ZipInfoオブジェクトにどんな情報が含まれているかについては、ドキュメントを参照されたい。

「解決!Python」のインデックス

解決!Python

Copyright© Digital Advantage Corp. All Rights Reserved.

スポンサーからのお知らせPR

注目のテーマ

AI for エンジニアリング
「サプライチェーン攻撃」対策
1P情シスのための脆弱性管理/対策の現実解
OSSのサプライチェーン管理、取るべきアクションとは
Microsoft & Windows最前線2024
システム開発ノウハウ 【発注ナビ】PR
あなたにおすすめの記事PR

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。