以下は『転送助手』のソースコード全文です:
import os
import shutil
import tkinter as tk
from tkinter import filedialog, messagebox
from collections import defaultdict
class FileMoverApp:
def __init__(self, master):
self.master = master
self.master.title("ファイル移動/コピーツール - 転送助手")
self.source_folder = ""
self.dest_folder = ""
self.extension_vars = {}
self.backup_log = defaultdict(list)
self.create_widgets()
def create_widgets(self):
# 対象フォルダ選択
tk.Button(self.master, text="対象フォルダ選択", command=self.select_source_folder).pack(pady=3)
self.source_label = tk.Label(self.master, text="対象フォルダ: 未選択", fg="gray")
self.source_label.pack()
# 処理先フォルダ選択
tk.Button(self.master, text="移動/コピー先フォルダ選択", command=self.select_dest_folder).pack(pady=3)
self.dest_label = tk.Label(self.master, text="処理先フォルダ: 未選択", fg="gray")
self.dest_label.pack()
# ファイル情報取得
tk.Button(self.master, text="ファイル情報取得", command=self.get_file_info).pack(pady=5)
self.extension_frame = tk.LabelFrame(self.master, text="拡張子の選択")
self.extension_frame.pack(padx=10, pady=5, fill="both")
# 処理方法(移動 or コピー)
self.action_var = tk.StringVar(value="move")
tk.Radiobutton(self.master, text="移動", variable=self.action_var, value="move").pack()
tk.Radiobutton(self.master, text="コピー", variable=self.action_var, value="copy").pack()
# 実行 & 元に戻す
tk.Button(self.master, text="実行", command=self.execute).pack(pady=5)
tk.Button(self.master, text="元に戻す", command=self.undo).pack(pady=5)
# 処理状況ウィンドウ
self.log_text = tk.Text(self.master, height=10, width=60)
self.log_text.pack(padx=10, pady=10)
self.log_text.insert(tk.END, "処理状況がここに表示されます。\n")
def log(self, message):
self.log_text.insert(tk.END, message + "\n")
self.log_text.see(tk.END)
def select_source_folder(self):
self.source_folder = filedialog.askdirectory(title="対象フォルダを選択")
if self.source_folder:
self.source_label.config(text=f"対象フォルダ: {self.source_folder}", fg="black")
def select_dest_folder(self):
self.dest_folder = filedialog.askdirectory(title="移動/コピー先フォルダを選択")
if self.dest_folder:
self.dest_label.config(text=f"処理先フォルダ: {self.dest_folder}", fg="black")
def get_file_info(self):
for widget in self.extension_frame.winfo_children():
widget.destroy()
self.extension_vars.clear()
if not self.source_folder:
messagebox.showwarning("警告", "対象フォルダを選択してください")
return
ext_set = set()
for filename in os.listdir(self.source_folder):
if os.path.isfile(os.path.join(self.source_folder, filename)):
_, ext = os.path.splitext(filename)
if ext:
ext_set.add(ext)
for ext in sorted(ext_set):
var = tk.BooleanVar()
tk.Checkbutton(self.extension_frame, text=ext, variable=var).pack(anchor="w")
self.extension_vars[ext] = var
def generate_unique_filename(self, folder, filename):
base, ext = os.path.splitext(filename)
counter = 1
new_filename = filename
while os.path.exists(os.path.join(folder, new_filename)):
new_filename = f"{base}({counter}){ext}"
counter += 1
return new_filename
def execute(self):
if not self.source_folder or not self.dest_folder:
messagebox.showwarning("警告", "対象フォルダと処理先フォルダを両方選択してください")
return
action = self.action_var.get()
selected_exts = [ext for ext, var in self.extension_vars.items() if var.get()]
if not selected_exts:
messagebox.showwarning("警告", "拡張子を選択してください")
return
self.log("処理開始...")
count = 0 # 処理件数カウンタ
for filename in os.listdir(self.source_folder):
filepath = os.path.join(self.source_folder, filename)
if not os.path.isfile(filepath):
continue
_, ext = os.path.splitext(filename)
if ext in selected_exts:
safe_filename = self.generate_unique_filename(self.dest_folder, filename)
dest_path = os.path.join(self.dest_folder, safe_filename)
if action == "move":
shutil.move(filepath, dest_path)
self.backup_log[safe_filename].append(filepath)
self.log(f"移動: {filename} → {safe_filename}")
elif action == "copy":
shutil.copy2(filepath, dest_path)
self.backup_log[safe_filename].append(None)
self.log(f"コピー: {filename} → {safe_filename}")
count += 1
self.log(f"処理完了。{count}個のファイルを{'移動' if action == 'move' else 'コピー'}しました。")
messagebox.showinfo("完了", f"{count}個のファイルを{'移動' if action == 'move' else 'コピー'}しました。")
def undo(self):
self.log("元に戻し中...")
for filename, paths in self.backup_log.items():
if paths[-1]: # move のとき
current_path = os.path.join(self.dest_folder, filename)
if os.path.exists(current_path):
shutil.move(current_path, paths[-1])
self.log(f"戻した: {filename}")
else: # copy のとき
copy_path = os.path.join(self.dest_folder, filename)
if os.path.exists(copy_path):
os.remove(copy_path)
self.log(f"削除: {filename}(コピー戻し)")
self.backup_log.clear()
self.log("元に戻しました。")
messagebox.showinfo("元に戻しました", "処理前の状態に戻しました。")
# アプリ起動
if __name__ == "__main__":
root = tk.Tk()
app = FileMoverApp(root)
root.mainloop()