Pythonでrarファイルの解凍をおこなうサンプル
Page content
Pythonでrarファイルの解凍をおこなう
rarfileライブラリを利用
import os
import rarfile
def safe_extract_rar(
rar_filepath,
output_dir,
max_total_size_mb=4096,
max_file_size_mb=1024
):
"""
RARファイルを安全に展開する
引数:
rar_filepath (str): RARファイルのパス
output_dir (str): 展開先のディレクトリ
max_total_size_mb (int): 合計ファイルサイズの上限 (MB)
max_file_size_mb (int): ファイル単位のサイズ上限 (MB)
戻り値:
bool: 全てのファイルが正常に展開された場合はTrue、それ以外はFalse
"""
# 展開先の絶対パスを取得し、存在しない場合は作成
safe_output_dir = os.path.abspath(output_dir)
os.makedirs(safe_output_dir, exist_ok=True)
max_total_bytes = max_total_size_mb * 1024 * 1024
# 【追加】ファイル単位の上限をバイトに変換
max_single_file_bytes = max_file_size_mb * 1024 * 1024
total_size = 0
is_success = True
try:
with rarfile.RarFile(rar_filepath) as rf:
for member in rf.infolist():
# (ファイル名デコード、パス、シンボリックリンクのチェック)
try:
filename = member.filename.encode('cp437').decode(
'utf-8', 'ignore'
)
except Exception:
filename = member.filename
full_path = os.path.join(safe_output_dir, filename)
dest_path = os.path.abspath(full_path)
if not dest_path.startswith(safe_output_dir + os.sep):
print(f"警告: 安全でないパスのためスキップ '{filename}'")
is_success = False
continue
if member.is_symlink():
print(f"警告: シンボリックリンクのためスキップ '{filename}'")
is_success = False
continue
if member.is_dir():
continue
# --- ここからサイズチェック ---
# 【追加】ファイル単位のサイズチェック
if member.file_size > max_single_file_bytes:
err_msg = (
f"エラー: ファイル '{filename}' のサイズが上限 "
f"{max_file_size_mb} MB を超えています。"
)
print(err_msg)
return False # 即座にFalseを返して終了
# 合計サイズチェック
total_size += member.file_size
if total_size > max_total_bytes:
err_msg = (
f"エラー: 合計サイズが上限 {max_total_size_mb} MB "
"を超えました。処理を中断します。"
)
print(err_msg)
return False
# 安全なファイルのみ展開
print(f"展開中: {filename}")
rf.extract(member, path=safe_output_dir)
return is_success
except FileNotFoundError:
print(f"エラー: RARファイルが見つかりません '{rar_filepath}'")
return False
except rarfile.BadRarFile:
err_msg = (
f"エラー: '{rar_filepath}' は不正なRARファイルか、"
"破損しています。"
)
print(err_msg)
return False
except rarfile.PasswordRequired:
print(f"エラー: '{rar_filepath}' はパスワードで保護されています。")
return False
except Exception as e:
print(f"予期せぬエラーが発生しました: {e}")
return False
- 相対指定により、展開先より上位ディレクトリに展開されるのを防止
- 文字化けを極力避けるコードを追加
- 展開時に巨大化するファイルへの対応
参考
- https://rarfile.readthedocs.io/api.html#rarfile-class:title
- 本ページのサンプルコードにはGoogleのGeminiを一部利用しています。