Pythonにおけるファイル操作は、標準ライブラリの充実により非常に効率的に行うことができます。
その中でも、ファイルやディレクトリのコピー、移動、削除、そしてアーカイブ(圧縮・展開)を直感的に扱えるのが shutil モジュールです。
日常的なスクリプト作成から大規模なバックアップシステムの構築まで、ファイルをまとめる作業は欠かせません。
本記事では、2026年現在の開発環境において標準的に利用されている shutil を用いたアーカイブ作成と展開の具体的な手順について解説します。
ZIPやTarといった主要なフォーマットへの対応方法だけでなく、ディレクトリ構造を保持したまま圧縮する際の細かな挙動についても、実装コードを交えて詳しく見ていきましょう。
shutilモジュールによるアーカイブ操作の概要
Pythonでファイルを圧縮・展開する場合、zipfile や tarfile といった専門のモジュールも存在します。
これらは非常に多機能ですが、一方で「特定のディレクトリを丸ごとZIPにする」といったシンプルなタスクに対しては、コードが冗長になりがちです。
そこで重宝するのが shutil(Shell Utilities) モジュールです。
このモジュールは高水準なファイル操作を提供しており、複雑なループ処理やファイルリストの作成を意識することなく、一行の関数呼び出しでアーカイブ作成や展開を完結させることができます。
主な利点は以下の通りです。
- ディレクトリ構造を再帰的に自動取得して圧縮できる
- 複数の圧縮形式(zip, tar, gztar, bztar, xztar)を共通のインターフェースで扱える
- 展開(解凍)処理もパスを指定するだけで完了する
- 標準ライブラリであるため、追加のライブラリインストールが不要
次セクションからは、具体的な関数とその使い方を詳しく解説します。
アーカイブ作成の基本:shutil.make_archive
アーカイブを作成する際に使用するのは shutil.make\_archive() 関数です。
この関数は、指定されたディレクトリの内容を指定されたフォーマットで一つのファイルにまとめます。
サポートされているフォーマットの確認
まず、自分の環境でどのようなフォーマットが利用可能かを確認しておきましょう。
環境(OSやインストールされているライブラリ)によって、利用できる圧縮形式が異なる場合があります。
以下のコードを実行することで、現在利用可能なアーカイブフォーマットの一覧を取得できます。
import shutil
# 利用可能なアーカイブフォーマットを取得
formats = shutil.get_archive_formats()
print("利用可能なフォーマット:")
for fmt, description in formats:
print(f"{fmt:10}: {description}")
利用可能なフォーマット:
bztar : bzip2'ed tar-file
gztar : gzip'ed tar-file
tar : uncompressed tar file
xztar : lzma'ed tar-file
zip : ZIP file
一般的には zip や gztar(.tar.gz)が広く使われています。
ZIP形式でのアーカイブ作成手順
最も一般的なZIP形式での作成例を見てみましょう。
例えば、data\_folder というディレクトリを backup.zip という名前でアーカイブする場合、以下のようなコードになります。
import shutil
import os
# 圧縮したい対象ディレクトリ
source_dir = 'my_project_data'
# 出力するアーカイブのファイル名(拡張子は自動付与されるため不要)
output_filename = 'backup_2026'
# ディレクトリの準備(デモ用)
if not os.path.exists(source_dir):
os.makedirs(source_dir)
with open(os.path.join(source_dir, 'test.txt'), 'w') as f:
f.write('Hello, Python 2026!')
# アーカイブ作成
# base_name: 作成するファイル名
# format: 'zip', 'tar', 'gztar' など
# root_dir: 圧縮対象のルートディレクトリ
archive_path = shutil.make_archive(output_filename, 'zip', root_dir=source_dir)
print(f"アーカイブが作成されました: {archive_path}")
アーカイブが作成されました: /path/to/your/directory/backup_2026.zip
注意点として、第一引数の base_name には拡張子を含めないようにしてください。 第二引数で指定したフォーマットに基づいて、自動的に .zip や .tar.gz が付与されます。
Tar形式(gztar)でのアーカイブ作成
Linux環境などでよく利用される .tar.gz 形式も、引数を変更するだけで簡単に作成できます。
import shutil
# gztar (tar.gz) 形式で作成
shutil.make_archive('logs_archive', 'gztar', root_dir='logs')
print("Tar.gz形式のアーカイブ作成が完了しました。")
このように、format 引数を変えるだけで内部的なアルゴリズムを切り替えられるのが shutil の強みです。
アーカイブ展開の基本:shutil.unpack_archive
作成されたアーカイブを元に戻す(展開する)には、shutil.unpack\_archive() を使用します。
この関数は、ファイル拡張子から自動的にフォーマットを判別してくれるため、非常にシンプルに記述できます。
展開可能なフォーマットの確認
作成時と同様に、展開可能なフォーマットも確認できます。
import shutil
# 展開可能なフォーマットの一覧
unpack_formats = shutil.get_unpack_formats()
for fmt, extensions, description in unpack_formats:
print(f"{fmt:10}: {extensions} - {description}")
アーカイブを特定のディレクトリに展開する
次に、実際にZIPファイルを展開するコードを確認しましょう。
import shutil
import os
# 展開するアーカイブファイル名
archive_file = 'backup_2026.zip'
# 展開先のディレクトリ
extract_dir = 'extracted_data'
# 展開実行
# filename: 展開対象のパス
# extract_dir: 展開先のパス(省略するとカレントディレクトリ)
shutil.unpack_archive(archive_file, extract_dir)
print(f"{archive_file} を {extract_dir} に展開しました。")
backup_2026.zip を extracted_data に展開しました。
extract_dir で指定したディレクトリが存在しない場合は、関数が自動的にディレクトリを作成してくれます。 これにより、事前に os.makedirs を呼ぶ手間が省けます。
実践的な応用例:バックアップスクリプトの作成
実務では、単一のディレクトリを固めるだけでなく、特定の構成でバックアップを取りたいケースが多いでしょう。
ここでは、shutil.make\_archive の重要な引数である root\_dir と base\_dir の使い分けについて詳しく解説します。
ディレクトリ構成の指定(root_dirとbase_dir)
この二つの引数の違いを理解することは、思い通りのアーカイブ構造を作るために非常に重要です。
- root\_dir: 圧縮処理を行う際の「作業ルートディレクトリ」を指定します。アーカイブ内のパスはこのディレクトリからの相対パスになります。
- base\_dir:
root\_dirから見て、実際にアーカイブに含めたいディレクトリのパスを指定します。
例えば、以下のような構造があるとします。
/home/user/projects/
myapp/
data/
logs/
src/
ここで、myapp ディレクトリの中身だけをアーカイブし、アーカイブを解凍した時に直下に data, logs, src が来るようにしたい場合は、root\_dir='myapp' を指定します。
一方で、アーカイブを解凍した時に myapp/ というディレクトリが一つあり、その中に中身が入っている状態にしたい場合は、以下のように記述します。
import shutil
# projectsディレクトリを作業ルートにする
# その中の myapp ディレクトリを圧縮対象にする
shutil.make_archive(
'project_backup',
'zip',
root_dir='/home/user/projects',
base_dir='myapp'
)
この使い分けを誤ると、「展開したら大量のファイルがカレントディレクトリに散らばってしまった」 あるいは 「深い階層構造がそのままアーカイブに入ってしまった」 といったトラブルの原因になります。
日時を付与した自動バックアップの実装
実際の運用で役立つ、実行時の日付をファイル名に含める実装例を紹介します。
import shutil
from datetime import datetime
import os
def backup_project(target_path, backup_dest):
"""
指定されたディレクトリをZIP圧縮してバックアップ先に保存する
"""
# 現在の日時を取得
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
# 対象ディレクトリ名を取得
base_name = os.path.basename(target_path.rstrip(os.sep))
# 保存先のフルパス(拡張子なし)
save_path = os.path.join(backup_dest, f"{base_name}_{timestamp}")
# バックアップ実行
# root_dirを対象の親ディレクトリに、base_dirを対象ディレクトリ自体にする
root_dir = os.path.dirname(target_path)
base_dir = os.path.basename(target_path)
result = shutil.make_archive(save_path, 'zip', root_dir=root_dir, base_dir=base_dir)
return result
# 使用例
try:
path = backup_project('./my_app_folder', './backups')
print(f"Successfully created: {path}")
except Exception as e:
print(f"Error occurred: {e}")
高度なカスタマイズと注意点
shutil は便利ですが、万能ではありません。
特定の高度な要件がある場合には注意が必要です。
エラーハンドリングと例外処理
ファイル操作には常にリスクが伴います。
例えば、圧縮対象のファイルが他のプロセスによってロックされていたり、ディスク容量が不足していたりする場合です。
shutil の操作は、失敗すると OSError やその派生クラスをスローします。
import shutil
import sys
try:
shutil.make_archive('protected_data', 'zip', '/root/secret')
except PermissionError:
print("エラー:権限がありません。管理者権限で実行してください。")
except FileNotFoundError:
print("エラー:対象のディレクトリが見つかりません。")
except Exception as e:
print(f"予期せぬエラーが発生しました: {e}")
大容量ファイルを扱う際の注意点
shutil.make\_archive は、内部的にすべてのファイルを走査してアーカイブを作成します。
数GBを超えるような極めて大きなディレクトリを扱う場合、以下の点に注意してください。
- 一時的なディスク使用量: 圧縮中のデータが一時的にストレージを圧迫することがあります。
- メモリ負荷:
shutil自体はストリーム処理を行いますが、大量のファイルエントリを管理するためにメモリ消費が増える場合があります。 - タイムアウト: ネットワーク経由のファイルシステム(NFSやSMB)上のデータを圧縮する場合、非常に時間がかかり、接続が切れるリスクがあります。
より詳細な制御(例:圧縮レベルの指定、特定のファイルを除外するフィルタリングなど)が必要な場合は、shutil ではなく、zipfile.ZipFile クラスなどを使用して、一つずつファイルを書き込む低水準な実装を検討してください。
セキュリティ上の懸念(Zip Slip脆弱性)
アーカイブの展開時には、セキュリティ上のリスクも考慮する必要があります。
特に、外部から取得した信頼できないアーカイブファイルを展開する場合、../ といった相対パスを含めることで展開先以外のファイルを上書きしようとする「Zip Slip」攻撃が知られています。
Python 3.12以降(およびバックポートされたバージョン)では、shutil.unpack\_archive も内部で安全な展開を試みますが、2026年現在でも、信頼できないソースからのアーカイブを扱う際は、展開前にファイルリストを検証する ことが推奨されます。
| 項目 | shutil (高水準) | zipfile/tarfile (低水準) |
|---|---|---|
| 学習コスト | 非常に低い | やや高い |
| コード量 | 1行 | 数行〜数十行 |
| 圧縮レベル指定 | 不可(デフォルトのみ) | 可能 |
| フィルタリング | 不可(丸ごと圧縮) | 可能(自由自在) |
| パスワード保護 | 非対応 | 対応(zipfile等) |
日常的な自動化スクリプトであれば、shutil で十分なケースがほとんどです。
まとめ
Pythonの shutil モジュールは、複雑なアーカイブ処理を極めてシンプルに記述できる強力なツールです。
shutil.make\_archive()を使えば、数行のコードでディレクトリをZIPやTar形式に圧縮できる。shutil.unpack\_archive()を使えば、形式を問わず簡単にファイルを展開できる。root\_dirとbase\_dirを正しく使い分けることで、アーカイブ内のディレクトリ構造を柔軟に制御できる。- 高度な圧縮設定やセキュリティ要件がある場合は、
zipfileなどの個別モジュールと併用するのがベスト。
ファイル圧縮・展開の自動化は、データ分析の前処理やサーバーのログ管理、定期的なバックアップなど、多くの場面で役立ちます。
まずは shutil で実装の手間を最小限に抑えつつ、効率的なPythonプログラミングを実践していきましょう。
