PythonにはZIPファイルを読み書きするためのzipfileモジュールが標準で付属している。これを使って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をクローズ
# 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
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ファイルにどんなメンバー(ファイル/ディレクトリ)が含まれているかを知るには、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ファイルを展開するには、以下の2つのメソッドを使える。
アーカイブに含まれる全てのファイルを展開するなら、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'…………') # パスワードを指定
なお、これらのメソッドでアーカイブを展開する際には注意点がある。それはアーカイブ内のメンバーの名前がフルパスのときには、それらはフルパスとしては扱われずに、現在の作業ディレクトリ以下に展開されるということだ(セキュリティ面を考慮して、このような振る舞いになっている。詳しくはドキュメントを参照されたい)。
アーカイブに含まれる特定のファイルだけを読み出して、その内容に従って何かの処理をしたいということもあるだろう。そうしたときには、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メソッドを呼び出す必要がある。
アーカイブのメンバーの詳細な情報を得るには、 以下の2つのメソッドを使える。
以下に例を示す。
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オブジェクトにどんな情報が含まれているかについては、ドキュメントを参照されたい。
Copyright© Digital Advantage Corp. All Rights Reserved.