🌊

Pythonで作る!分割して自動でZIP化するファイル整理ツール📦

2024/12/30に公開

はじめに

「たくさんのファイルをまとめて送りたいけど、1つのZIPファイルだと重すぎる...」
「手作業でファイルを圧縮するのが面倒...」

そんな悩みを解決するツールを、今回はPythonで作っていきます。
プログラミング初心者の方でも理解できるように、基礎から丁寧に解説していきますので、ぜひ最後までお付き合いください!

このツールは何ができるの?

まず、このツールが何をしてくれるのか、具体例で見てみましょう。

たとえば、フォルダの中に50個の写真ファイルがあるとします:

写真1.jpg
写真2.jpg
写真3.jpg
...(たくさんの写真)
写真50.jpg

このツールを使うと、これらが自動的に10個ずつに分けられて、以下のようなZIPファイルができあがります:

archive_1.zip(写真1~写真10が入っています)
archive_2.zip(写真11~写真20が入っています)
archive_3.zip(写真21~写真30が入っています)
archive_4.zip(写真31~写真40が入っています)
archive_5.zip(写真41~写真50が入っています)

この機能には、以下のような特徴があります:

  1. マウスで操作できる画面付き(専門的にはGUIと呼びます)
  2. フォルダを選ぶだけの簡単操作
  3. エラーが起きても安全に停止する機能付き
  4. 追加でソフトをインストールする必要なし

必要な準備

このツールを動かすために必要なのは、Pythonだけです!
以下のライブラリは、Pythonに最初から入っているので、追加でインストールする必要はありません:

import os              # ファイルやフォルダを扱うための機能
import zipfile         # ZIPファイルを作るための機能
from pathlib import Path    # フォルダやファイルの場所を扱いやすくする機能
import tkinter as tk   # 画面(GUI)を作るための機能
from tkinter import filedialog, messagebox  # フォルダを選ぶ画面を作る機能
import traceback      # エラーが起きたときの情報を詳しく表示する機能

コードを詳しく解説!

1. ファイルをZIPにまとめる部分

まずは、一番重要な「ファイルをZIPにまとめる」部分を見ていきましょう:

def zip_files_in_groups(input_folder, output_folder, files_per_zip=10):
    # フォルダの場所を扱いやすい形式に変換
    input_path = Path(input_folder)
    output_path = Path(output_folder)
    
    # フォルダの中からファイルの一覧を取得
    all_files = [f for f in input_path.iterdir() if f.is_file()]
   
    # ファイルを10個ずつ処理していく
    for i in range(0, len(all_files), files_per_zip):
        # ZIPファイルの名前を決める(例:archive_1.zip)
        zip_name = f"archive_{i // files_per_zip + 1}.zip"
        zip_path = output_path / zip_name
       
        # ZIPファイルを作って、中にファイルを入れていく
        with zipfile.ZipFile(zip_path, 'w') as zipf:
            for file in all_files[i:i + files_per_zip]:
                zipf.write(file, file.name)

このコードは、以下のような手順で動いています:

  1. フォルダの場所を設定

    • Path(input_folder)で、入力フォルダの場所を指定
    • Path(output_folder)で、作成したZIPファイルを保存する場所を指定
  2. ファイルの一覧を取得

    • input_path.iterdir()で、フォルダの中身を順番に見ていく
    • if f.is_file()で、フォルダではなくファイルだけを選ぶ
  3. 10個ずつグループ化

    • range(0, len(all_files), files_per_zip)で、10個ずつ区切る
    • たとえば50個のファイルなら、0-9、10-19、20-29、30-39、40-49の5グループに分ける
  4. ZIPファイルの作成

    • zipfile.ZipFile(zip_path, 'w')で新しいZIPファイルを作る
    • zipf.write(file, file.name)で、ファイルをZIPの中に入れる

2. フォルダを選ぶ画面の部分

次は、フォルダを選ぶための画面を作る部分です:

def select_folder(title):
    try:
        # 画面を準備
        root = tk.Tk()
        root.withdraw()  # 余計な画面を隠す
        
        # フォルダを選ぶ画面を表示
        folder_path = filedialog.askdirectory(title=title)
        return folder_path
        
    except Exception as e:
        # エラーが起きたときの処理
        print(f"フォルダ選択中にエラーが発生しました: {str(e)}")
        print(traceback.format_exc())
        return None

この部分は、以下のような働きをします:

  1. 画面の準備

    • tk.Tk()で、画面の土台を作る
    • root.withdraw()で、必要のない画面を隠す
  2. フォルダ選択画面の表示

    • filedialog.askdirectoryで、フォルダを選ぶ画面を表示
    • 選んだフォルダの場所がfolder_pathに保存される
  3. エラー対策

    • try:except:で、エラーが起きたときの対策をする
    • エラーが起きたら、その内容を画面に表示

3. メインの処理部分

最後に、全体の流れを管理する部分を見ていきましょう:

def main():
    try:
        print("GUIを初期化中...")
        root = tk.Tk()
        root.withdraw()
        
        print("入力フォルダを選んでください...")
        input_folder = select_folder("ZIPにしたいファイルがあるフォルダを選択")
        if not input_folder:
            print("フォルダが選択されませんでした")
            return
            
        print("保存先フォルダを選んでください...")
        output_folder = select_folder("ZIPファイルを保存するフォルダを選択")
        if not output_folder:
            print("フォルダが選択されませんでした")
            return
            
        print("ZIP作成を開始します...")
        zip_files_in_groups(input_folder, output_folder)
        print("完了しました!")
        messagebox.showinfo("完了", "ファイルのZIP化が完了しました")
        
    except Exception as e:
        error_message = f"エラーが発生しました: {str(e)}\n\n{traceback.format_exc()}"
        print(error_message)
        messagebox.showerror("エラー", error_message)

この部分は、以下の順番で動きます:

  1. 準備

    • 画面の準備をする
    • 途中でエラーが起きた場合の対策をする
  2. フォルダの選択

    • ZIPにしたいファイルがあるフォルダを選んでもらう
    • ZIPファイルを保存するフォルダを選んでもらう
  3. ZIP作成

    • 選んだフォルダの中のファイルをZIP化
    • 完了したら知らせる
  4. エラー対策

    • 問題が起きたら、分かりやすいメッセージを表示

使い方の手順

  1. プログラムを実行します
  2. 「ZIPにしたいファイルがあるフォルダを選択」という画面が表示されます
  3. フォルダを選んで「OK」をクリック
  4. 「ZIPファイルを保存するフォルダを選択」という画面が表示されます
  5. 保存先のフォルダを選んで「OK」をクリック
  6. 自動的にZIPファイルが作られます
  7. 「完了しました!」というメッセージが表示されます

こんなときはどうする?(よくある質問)

Q1: エラーが表示されました。どうすればいいですか?
A1: エラーメッセージをよく読んで、以下を確認しましょう:

  • フォルダは正しく選べていますか?
  • フォルダの中にファイルはありますか?
  • 選んだフォルダに書き込み権限はありますか?

Q2: なぜ10個ずつに分けるのですか?
A2: 10個は一般的に扱いやすい数として設定していますが、この数は変更できます。

Q3: 日本語のファイル名でも大丈夫ですか?
A3: はい、問題なく処理できます。

できることを増やすヒント(上級者向け)

このツールは、以下のように機能を追加できます:

  1. 1つのZIPファイルに入れるファイル数を変更
# 20個ずつにしたい場合
zip_files_in_groups(input_folder, output_folder, files_per_zip=20)
  1. 特定の種類のファイルだけを選ぶ
# 写真(.jpg)だけを選ぶ場合
all_files = [f for f in input_path.iterdir() if f.is_file() and f.suffix == '.jpg']

注意点

  1. 同じ名前のZIPファイルがある場合は上書きされます
  2. とても大きなファイルの場合は、処理に時間がかかることがあります
  3. パソコンのメモリ(作業領域)に余裕があるか確認しましょう

まとめ

このツールを使うことで、以下のことが簡単にできるようになります:

  1. 大量のファイルを自動的に整理
  2. 手作業での圧縮作業から解放
  3. メールで送りやすい大きさのZIPファイルを作成

特に以下のような場面で役立ちます:

  • たくさんの写真をまとめるとき
  • 仕事の資料を整理するとき
  • メールで大量のファイルを送るとき

ぜひこのツールを使って、効率的なファイル管理を実現してください!分からないことがあれば、コメント欄でお気軽に質問してくださいね😊

コード全文

import os
import zipfile
from pathlib import Path
import tkinter as tk
from tkinter import filedialog, messagebox
import traceback

def zip_files_in_groups(input_folder, output_folder, files_per_zip=10):
    input_path = Path(input_folder)
    output_path = Path(output_folder)
    all_files = [f for f in input_path.iterdir() if f.is_file()]
    
    for i in range(0, len(all_files), files_per_zip):
        zip_name = f"archive_{i // files_per_zip + 1}.zip"
        zip_path = output_path / zip_name
        
        with zipfile.ZipFile(zip_path, 'w') as zipf:
            for file in all_files[i:i + files_per_zip]:
                zipf.write(file, file.name)
        
        print(f"Created {zip_name} with {min(files_per_zip, len(all_files) - i)} files")

def select_folder(title):
    try:
        root = tk.Tk()
        root.withdraw()  # メインウィンドウを非表示にする
        folder_path = filedialog.askdirectory(title=title)
        return folder_path
    except Exception as e:
        print(f"フォルダ選択中にエラーが発生しました: {str(e)}")
        print(traceback.format_exc())
        return None

def main():
    try:
        print("GUIを初期化中...")
        root = tk.Tk()
        root.withdraw()

        print("入力フォルダの選択ダイアログを表示中...")
        input_folder = select_folder("入力フォルダを選択してください")
        if not input_folder:
            print("入力フォルダが選択されませんでした。")
            return

        print("出力フォルダの選択ダイアログを表示中...")
        output_folder = select_folder("出力フォルダを選択してください")
        if not output_folder:
            print("出力フォルダが選択されませんでした。")
            return

        print("ZIP処理を開始します...")
        zip_files_in_groups(input_folder, output_folder)
        print("ZIP処理が完了しました。")
        messagebox.showinfo("完了", "ファイルのZIP化が完了しました。")
    except Exception as e:
        error_message = f"処理中にエラーが発生しました: {str(e)}\n\n{traceback.format_exc()}"
        print(error_message)
        messagebox.showerror("エラー", error_message)

if __name__ == "__main__":
    main()
    input("Enterキーを押して終了してください...")

Discussion