[解決!Python]py7zrパッケージを使って7-Zip(.7z)形式のアーカイブにファイルを圧縮するには解決!Python

Pythonで7-Zip(.7z)形式のアーカイブを作成し、そこにファイルを書き出すにはpy7zrパッケージのSevenZipFileクラスを使うのが便利だ。その基本的な使い方を紹介する。

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

連載目次

# 準備
from pathlib import Path
Path('test').mkdir(exist_ok=True)
Path('test/foo.txt').write_text('foo')
Path('test/bar.txt').write_text('bar')
Path('test/baz.bin').write_bytes(b'0123456789')
Path('test.txt').write_text('test')

from py7zr import SevenZipFile

# 7z形式に圧縮
archive = SevenZipFile('target.7z', 'w')
archive.write('test/foo.txt'# ファイルをアーカイブに追加
archive.write('test/bar.txt', arcname='bar'# アーカイブ名を指定
archive.write('test/baz.bin'# アーカイブ名を指定
archive.close()

archive = SevenZipFile('target.7z', 'w')
archive.writeall('test'# testディレクトリ以下を全てアーカイブ
archive.close()

# コンテキストマネジャーとして使用
with SevenZipFile('target.7z', 'w') as archive:
    archive.writeall('test'# testディレクトリ以下を全てアーカイブ

with SevenZipFile('target.7z', 'w') as archive:
    archive.writeall('test', arcname='data'# アーカイブ名を指定

with SevenZipFile('target.7z', 'w') as archive:
    archive.writeall('test', arcname=''# アーカイブ名を空にする

# アーカイブに追記
with SevenZipFile('target.7z', 'a') as archive:  # 追記モード
    archive.write('test.txt'# ファイルをアーカイブに追加

# 排他モードでのアーカイブ作成は未サポート(NotImplementedError例外)
with SevenZipFile('target.7z', mode='x') as archive:
    archive.writeall('test')

# パスワードの指定
with SevenZipFile('target.7z', 'w', password='password') as archive:
    archive.writeall('test')

# 圧縮方法の指定
from py7zr import FILTER_LZMA2, FILTER_DEFLATE
filters = [{'id': FILTER_DEFLATE}]
with SevenZipFile('target.7z', 'w', filters=filters) as archive:
    archive.writeall('test')


py7zrパッケージ

 7-Zipはアーカイバ(ファイルを圧縮、展開するソフトウェア)であり、オープンソースのフリーソフトウェアとしてWindows用に配布されている。7-Zipが取り扱うアーカイブ(拡張子は「.7z」)をPythonから扱うにはPyPIなどで配布されているpy7zrを使用する。本稿では7-Zipアーカイブの作成について解説する。7-Zipアーカイブの読み取りや展開については次回取り上げる。

 py7zrパッケージを使用するには「pip install py7zr」「py -m pip install py7zr」などのコマンドラインを実行してあらかじめこれをインストールしておく必要がある。また、ここでは以下のコードにより、アーカイブに格納するテストファイルを作成している(testディレクトリ以下に2つのテキストファイルと1つのバイナリファイルを作成し、カレントディレクトリに1つのテキストファイルを作成)。

from pathlib import Path
Path('test').mkdir(exist_ok=True)
Path('test/foo.txt').write_text('foo')
Path('test/bar.txt').write_text('bar')
Path('test/baz.bin').write_bytes(b'0123456789')
Path('test.txt').write_text('test')


 py7zrをインストール(して、py7zrコマンドのパスを環境変数PATHに追加)するとコマンドラインからその機能を使えるようになるが、これについては特に説明しない。ただし、実行結果の画面ではこのコマンドを使い、作成されたアーカイブの情報を参照する。

py7zr.SevenZipFileクラス

 py7zrパッケージはSevenZipFileクラスを提供しており、7-Zip(.7z)形式のアーカイブの読み取りや作成、展開、圧縮などの作業の大半はこのクラスのインスタンスを使って行える。以下にインスタンス生成の構文を示す。

py7zr.SevenZipFile(file, mode='r', filters=None, dereference=False, password=None)


 パラメーターの意味は次の通り。

  • file:アーカイブのファイル名を指定する
  • mode:アーカイブを読み込みモード('r')、書き込みモード('w')、追記モード('a')のどのモードでオープンするかの指定
  • filters:アーカイブにファイルを書き込む際の圧縮方法の指定
  • dereference:シンボリックリンクやハードリンクされているファイルについて、書き込み時にアーカイブにリンク先の実態を含めるか、リンクを含めるかの指定
  • password:パスワードの指定

 作成したSevenZipFileクラスのインスタンスでcloseメソッドを呼び出すことで、アーカイブの操作は終了する。また、後述するようにこのクラスはコンテキストマネジャーとして機能するので「with SevenZipFile(……):」のような記述により、closeメソッドの明示的な呼び出しを省略できる。

ファイルの圧縮

 ファイルを圧縮してアーカイブに書き込むには、アーカイブを書き込みモードでオープンし、writeメソッドまたはwriteallメソッドに圧縮したいファイルを指定する。writeメソッドは単一のファイルまたはディレクトリをアーカイブに書き込む。writeallメソッドにディレクトリを指定することで、そのディレクトリ以下のファイル/ディレクトリが再帰的にアーカイブへ書き出される。

SevenZipFile.write(filename, arcname=None)
SevenZipFile.writeall(filename, arcname=None)


 writeメソッドにディレクトリの名前を指定すると、そのディレクトリだけがアーカイブに追加される点には注意しよう。ディレクトリ以下を再帰的に追加するのであれば、writeallメソッドにそのディレクトリを指定する。

 SevenZipFileクラスのインスタンスを作成し(アーカイブを作成し)、そこにwriteメソッドでファイルを個別に追加していくコードの例を以下に示す。

from py7zr import SevenZipFile

archive = SevenZipFile('target.7z', 'w')
archive.write('test/foo.txt'# ファイルをアーカイブに追加
archive.write('test/bar.txt', arcname='bar'# アーカイブ名を指定
archive.write('test/baz.bin')
archive.close()


 「archive.write('test/bar.txt', arcname='bar')」行ではarcnameパラメーターに「test/bar.txt」ファイルのアーカイブ名を「bar」として指定している。これがどんな意味を持つかは下の実行結果をご覧いただきたい。

 以下はVisual Studio Codeで上記コードを実行し、そのターミナルでpy7zrコマンドを使ってアーカイブの内容を一覧したところだ(「py7zr l アーカイブ」コマンドでアーカイブの内容を表示)。

実行結果 実行結果

 py7zrコマンドの実行結果を見ると、「test/bar.txt」ファイルのアーカイブ内での名前が「bar」になっていることが分かる。名前にディレクトリが含まれていないので、このアーカイブを展開すると、もともと「test/bar.txt」だったファイルはカレントディレクトリに「bar」として展開されることになる。何らかの事情で当初のファイル階層とは異なる階層にファイルを置きたいなどの場合にはarcnameパラメーターを使うようにしよう。

 以下はwriteallメソッドでtestディレクトリ以下をアーカイブに書き出すコードの例だ。

from py7zr import SevenZipFile

archive = SevenZipFile('target.7z', 'w')
archive.writeall('test'# testディレクトリ以下を全てアーカイブ
archive.close()


 以下に実行結果を示す。

実行結果 実行結果

 testディレクトリ自体もアーカイブに追加されている点と、先ほどとは異なり、arcnameパラメーターに名前を指定していないので、全てのファイルがtestディレクトリ以下にあるファイルとして追加されている点に注意しよう。

コンテキストマネジャーとして使用

 既に述べたがSevenZipFileクラスのインスタンスはコンテキストマネジャーとして機能する。そのため、上で見たコードは次のように記述できる。

with SevenZipFile('target.7z', 'w') as archive:
    archive.writeall('test'# testディレクトリ以下を全てアーカイブ


 なお、writeallメソッドでディレクトリ名を指定した際に、同時にarcnameパラメーターを指定すると、アーカイブ内でのディレクトリ名がarcnameパラメーターに指定したものに置き換えられる。

with SevenZipFile('target.7z', 'w') as archive:
    archive.writeall('test', arcname='data'# アーカイブ名を指定


 この例ではtestディレクトリの内容をまとめてアーカイブに追加するが、このときにarcnameパラメーターに「data」を指定している。これにより、アーカイブ内での名前が次にように変更される。

実行結果 実行結果

 「test」が「data」に変わっている点に注目しよう。特定のディレクトリを指定してアーカイブに追加するが、展開時にはカレントディレクトリ以下にファイルを置きたいときには次のようにarcnameに空文字列を指定する。

with SevenZipFile('target.7z', 'w') as archive:
    archive.writeall('test', arcname=''# アーカイブ名を空にする


アーカイブへの追記

 アーカイブにファイルを追記するときには、SevenZipFileクラスのインスタンス生成時にmodeパラメーターに'a'を指定して、writeメソッドかwriteallメソッドでアーカイブにファイル(やディレクトリ)を書き出す。

with SevenZipFile('target.7z', 'a') as archive:  # 追記モード
    archive.write('test.txt'# ファイルをアーカイブに追加


 先ほどのコード(arcnameパラメーターに空文字列を指定した例)の直後に上のコードを実行すると、アーカイブの内容は次のようになる。

実行結果 実行結果

 アーカイブにファイルが追加されたこと(と、先ほどの例でアーカイブのファイル名からディレクトリ名がなくなっていること)が分かる。

 なお、アーカイブを排他的に作成しようとして、modeパラメーターに'x'を指定するとNotImplementedError例外が発生するので注意すること。

with SevenZipFile('target.7z', mode='x') as archive:
    archive.writeall('test')


パスワードの指定

 作成するアーカイブにパスワードを設定するにはSevenZipFileクラスのインスタンス生成時にpasswordパラメーターを使用する。

with SevenZipFile('target.7z', 'w', password='password') as archive:
    archive.writeall('test')


 このようにして作成したアーカイブはパスワードなしでも内容を確認できるが、展開するにはパスワードを指定する必要がある。

実行結果 実行結果

 実行結果の[ターミナル]タブを見ると、「py7zr l target.7z」コマンドではパスワードを指定せずともその内容を確認できている。しかし、「py7zr x target.7z」コマンドで展開しようとしたところでパスワードを指定していないので処理が中断されている。最後の「py7zr x target.7z --password」コマンドの実行により、パスワードを入力するプロンプトが表示された。

圧縮方法の指定

 圧縮方法を指定するには、filtersパラメーターに使用するアルゴリズムを指定する。以下に例を示す。

from py7zr import FILTER_LZMA2, FILTER_DEFLATE

filters = [{'id': FILTER_DEFLATE}]
with SevenZipFile('target.7z', 'w', filters=filters) as archive:
    archive.writeall('test')


 これはpy7zrのデフォルトの圧縮方法であるLZMA2を使わずに、圧縮方法としてDEFLATEを指定する例だ。詳細についてはpy7zrのドキュメント「Compression Methods」を参照されたい。

 上のコードを実行してアーカイブを作成し、「py7zr t target.7z」コマンドでアーカイブの情報を表示したのが以下の画像だ。

実行結果 実行結果

 「Method」が「DEFLATE」になっていることが分かるだろう。

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

解決!Python

Copyright© Digital Advantage Corp. All Rights Reserved.

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

注目のテーマ

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

RSSについて

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

メールマガジン登録

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