🧊

【Python】ちがう階層にある、すべてのzipファイルを解凍したい!

2022/08/09に公開1

こんにちはnamiki_iです!

データ圧縮やアーカイブのフォーマット形式として広く普及しているzip形式のファイルを一度に解凍する方法Pythonで実装したのでご紹介します!

実現したいこと

今回実現したいことは以下になります.

1. 任意のフォルダーに含まれているすべてのzipファイルの一括解凍

2. 解凍した中身は元のzipファイルと同階層に新しくフォルダーを作り格納する

同じ階層に含まれているzipファイルを解凍する方法はネット上で解決方法が紹介されていますが、
複数の階層を持つフォルダーの中のzipファイルを探索して解凍する方法が簡単には見つからなかったので実装してみました.

さらに、解凍した中身はzipファイルがあった階層とおなじ階層にzipファイルと同じ名前のフォルダーに格納します

イメージとしては以下の通りです.

解凍前
  • Folder1
    • file1.zip
    • Folder2
      • file2.zip
      • Folder3
        • file3.zip
解凍後
  • Folder1
    • file1.zip
    • file1
      • file1.zipを解凍した中身
    • Folder2
      • file2.zip
      • file2
        • file2.zipを解凍した中身
      • Folder3
        • file3.zip
        • file3
          • file3.zipを解凍した中身

解決方法1

ぶっちゃけ、ほとんどの場合はこちらで解決できます.

$ find ./ -name '*.zip' -execdir unzip {} \;

出典は以下のZenn記事になります.
https://zenn.dev/pinto0309/articles/c6f38abd082000

私も最初はこの方法を見つけて解決したつもりで安堵していたのですが、日本語名を含むファイルの解凍に失敗することがあったので別の方法を探す必要がでてきました...

解決方法2

シェルでの解決も候補の一つではあったのですが、Pythonに使い慣れているので参考文献をもとにPythonで実装しました.

コードは以下の通りです.

# -*- coding: utf-8 -*-
import os
import glob
from zipfile import ZipFile

# 解凍したいフォルダー(ディレクトリ)を指定する
#   指定したフォルダーの中に含まれるすべてのzipファイルを探索します.

dir  = "./"#相対パスを指定

# 解凍したいzipファイルのlistを作成する.
files = glob.glob(os.path.join(dir, '**/*.zip'), recursive=True)

## 対象ファイルを表示する.(実行する場合はコメントアウトを解除する.)
######################
# print("対象zipファイルは以下") 
# for file in files:
#     print(file)
######################

# 解凍する
print("Unzip start")
for file in files:
    output_pass = file.split(".zip")[0] #zipファイルと同じ名前のフォルダーを作成し解凍結果を格納する.
    with ZipFile(file) as zip:
        zip.extractall(output_pass)

print("Unzip finished")

実行方法

上のサンプルコードをそのまま使用する場合は、サンプルコードを解凍したいフォルダーの一番上の階層に置きます.
その後、サンプルコードをPythonの実行コードで実行すれば完了です.
イメージとしては以下です.

  • Folder1
    • サンプルコード.py
    • file1.zip
    • Folder2
      • file2.zip
      • Folder3
        • file3.zip

コードの解説

1.フォルダーの指定

まずは, 以下の部分でディレクトリを相対パスで指定します.(相対パスの解説は省略します.)
dir = "./"#相対パスを指定
サンプルコードでは、サンプルコードをフォルダーの一番上の階層に配置することを想定していますが、相対パスを指定することで任意のフォルダーを対象にすることができます.

2. zipファイルの探索

files = glob.glob(os.path.join(dir, '**/*.zip'), recursive=True)
この部分で指定したフォルダーの中のzipファイルを探索し、そのパスをlist形式でfilesに格納します.

3. 解凍

filesに含まれているパスを1個ずつ解凍します.

for file in files:
    output_pass = file.split(".zip")[0] #zipファイルと同じ名前のフォルダーを作成し解凍結果を格納する.
    with ZipFile(file) as zip:
        zip.extractall(output_pass)

解凍した中身は以下の部分で実装するように、zipファイル名と同じフォルダーを作成し、その中に解凍した中身を格納します。

output_pass = file.split(".zip")[0]

参考文献

https://zenn.dev/pinto0309/articles/c6f38abd082000
https://note.nkmk.me/python-glob-usage/
https://algorithm.joho.info/programming/python/folder-zip-py/

いかがでしたか?
今回は階層が分散しているフォルダーに含まれるzipファイルの一括解凍のご紹介をしました.
ご不明点があればコメントお願いします!

Discussion

くろねこくろねこ

こんにちは!とても便利なコードの共有をありがとうございました!
勉強不足で恐縮ですが、解凍し中身を格納後、zipファイルを削除するにはそのようなコードが必要かおわかりになりますでしょうか