import os import shutil import sys import pathlib import subprocess from io import BytesIO current_mode = None def force_close_handles(folder_path): try: import psutil closed_count = 0 for proc in psutil.process_iter(['pid', 'name']): try: for item in proc.open_files(): if folder_path.lower() in item.path.lower(): proc.kill() closed_count += 1 print(f"[系统] 已关闭占用进程: {proc.info['name']} (PID: {proc.info['pid']})") break except (psutil.NoSuchProcess, psutil.AccessDenied): pass if closed_count > 0: import time time.sleep(0.5) return closed_count > 0 except ImportError: return False def delete_system_files(folder_path): system_files = ['thumbs.db', 'desktop.ini', '.ds_store', 'thumbs.db:encryptable'] deleted_count = 0 try: for root, dirs, files in os.walk(folder_path): for filename in files: if filename.lower() in system_files or filename.startswith('._'): file_path = os.path.join(root, filename) try: os.chmod(file_path, 0o777) os.remove(file_path) deleted_count += 1 except: pass if deleted_count > 0: print(f"[系统] 已清理 {deleted_count} 个系统隐藏文件") except: pass def get_next_log_index(): index = 1 while pathlib.Path(f"path_list_{index}.log").exists(): index += 1 return index def open_folder(path: pathlib.Path): if sys.platform.startswith("win"): os.startfile(path) elif sys.platform.startswith("darwin"): subprocess.run(["open", path]) else: subprocess.run(["xdg-open", path]) def mode_wb(): print("\n" + "="*60) print("已进入 WB 模式 - 文件夹批处理工具") print("功能:复制文件夹 -> 重命名文件夹和内部文件 -> 标记原文件夹") print("="*60) while True: print("\n================== 新的工作任务 ==================") work_dir = input("请输入主文件夹路径 (工作路径, 输入 :back 返回): ").strip() if work_dir == ":back": return if not os.path.exists(work_dir): print(f"[错误] 工作路径 '{work_dir}' 不存在,请先创建或检查路径。") continue print(f"[系统] 已锁定工作路径: {work_dir}") process_wb_folder(work_dir) print("\n------------------------------------------------------") while True: choice = input("任务结束。输入 :back 返回主菜单,或输入 :y 开启下一个工作路径: ").strip().lower() if choice == ":back": return elif choice == ":y": break else: print("输入无效,请输入 :back 或 :y") def process_wb_folder(work_dir): while True: print("\n------------------------------------------------------") src_path_input = input("请输入待复制的文件夹路径 (输入 :end 结束当前阶段): ").strip() if src_path_input == ":end": return if not os.path.exists(src_path_input): print(f"[错误] 路径 '{src_path_input}' 不存在,请重新输入。") continue target_name = input("请输入想要重命名的名称: ").strip() if not target_name: print("[错误] 名称不能为空。") continue dest_path = os.path.join(work_dir, target_name) try: if os.path.exists(dest_path): print(f"[错误] 目标文件夹 '{dest_path}' 已经在工作路径下存在,跳过此任务。") continue shutil.copytree(src_path_input, dest_path) print(f"[成功] 文件夹已复制并重命名为: {target_name}") all_items = os.listdir(dest_path) files = [] for f in all_items: full_path = os.path.join(dest_path, f) if os.path.isfile(full_path) and not f.startswith('.') and f.lower() not in ['thumbs.db', 'desktop.ini']: files.append(f) files.sort() count = 1 for filename in files: file_ext = os.path.splitext(filename)[1] new_filename = f"{target_name} {count}{file_ext}" old_file_path = os.path.join(dest_path, filename) new_file_path = os.path.join(dest_path, new_filename) os.rename(old_file_path, new_file_path) count += 1 print(f"[成功] 已重命名文件夹内的 {count-1} 个文件 (从 1 开始)。") clean_src_path = os.path.normpath(src_path_input) parent_dir = os.path.dirname(clean_src_path) original_folder_name = os.path.basename(clean_src_path) new_src_folder_name = "used_" + original_folder_name used_src_path = os.path.join(parent_dir, new_src_folder_name) try: delete_system_files(clean_src_path) os.rename(clean_src_path, used_src_path) print(f"[成功] 原文件夹已重命名为: {new_src_folder_name}") except PermissionError: print(f"[警告] 文件夹被占用,尝试强制解锁...") if force_close_handles(clean_src_path): try: os.rename(clean_src_path, used_src_path) print(f"[成功] 原文件夹已重命名为: {new_src_folder_name}") except Exception as e: print(f"[警告] 解锁后仍无法重命名: {e}") print(f" 原文件夹路径: {clean_src_path}") else: print(f"[警告] 无法重命名原文件夹为 used_ 开头(需要安装psutil库)") print(f" 安装命令: python.exe -m pip install psutil --break-system-packages") print(f" 原文件夹路径: {clean_src_path}") except FileExistsError: print(f"[警告] 目标名称 '{new_src_folder_name}' 已存在,跳过重命名") except Exception as e: print(f"[警告] 重命名原文件夹时出错: {e}") except PermissionError: print(f"[错误] 权限不足,无法访问或复制文件夹") except Exception as e: print(f"[异常] 发生未知错误: {e}") def mode_path(): print("\n" + "="*60) print("已进入 PATH 模式 - 文件夹批量创建工具") print("操作指南:") print("1. 输入路径后按回车 -> 加入待创建队列") print("2. 输入 ':y' 并回车 -> 立即批量创建队列中所有文件夹") print("3. 输入 ':open x' -> 打开 path_list_x.log 中的所有文件夹") print("4. 输入 ':back' -> 返回主菜单") print("="*60 + "\n") path_queue = [] while True: queue_count = len(path_queue) prompt = f"[{queue_count} 个待创建] >>> 请输入路径: " raw_path = input(prompt).strip() if raw_path.lower().startswith(":open"): parts = raw_path.split() if len(parts) != 2 or not parts[1].isdigit(): print("用法错误,应为 :open x") continue log_index = parts[1] log_file = pathlib.Path(f"path_list_{log_index}.log") if not log_file.exists(): print(f"日志文件不存在: {log_file}") continue print(f"正在打开 {log_file} 中的文件夹...") with log_file.open("r", encoding="utf-8") as f: for line in f: folder = pathlib.Path(line.strip()) if folder.exists(): open_folder(folder) else: print(f"路径不存在,已跳过: {folder}") continue if raw_path.lower() == ':y': if not path_queue: print("警告:队列为空,没有什么可创建的。") print("-" * 30) continue print(f"\n开始执行批量创建,共 {len(path_queue)} 个任务...") success_count = 0 created_paths = [] for p_str in path_queue: target_path = pathlib.Path(p_str) try: target_path.mkdir(parents=True, exist_ok=True) print(f" [OK] Created: {target_path}") success_count += 1 created_paths.append(str(target_path)) except Exception as e: print(f" [ERR] Failed: {target_path} | 原因: {e}") print(f"\n执行完毕。成功: {success_count} / 总计: {len(path_queue)}") log_index = get_next_log_index() log_file = pathlib.Path(f"path_list_{log_index}.log") with log_file.open("w", encoding="utf-8") as f: for p in created_paths: f.write(p + "\n") print(f"已生成日志文件: {log_file}") print("-" * 30) path_queue.clear() continue if raw_path.lower() == ':back': if path_queue: confirm = input(f"队列中还有 {len(path_queue)} 个路径未创建,确定要返回吗?(y/n): ") if confirm.lower() != 'y': continue return if not raw_path: continue path_queue.append(raw_path) print(f"已加入队列: '{raw_path}'") print("-" * 20) def mode_photo(): print("\n" + "="*60) print("已进入 PHOTO 模式 - 图片左右镜像工具") print("功能:批量将文件夹中的所有图片进行左右镜像翻转") print("支持格式:.jpg, .jpeg, .png, .bmp, .gif, .webp, .tif, .tiff") print("操作指南:") print("1. 输入文件夹路径后按回车 -> 加入待处理队列") print("2. 输入 ':y' 并回车 -> 批量处理队列中所有文件夹的图片") print("3. 输入 ':back' -> 返回主菜单") print("="*60 + "\n") try: from PIL import Image except ImportError: print("[错误] 未检测到 Pillow 库!") print("请先安装 Pillow:") print(" python.exe -m pip install pillow") print("或者手动下载 pillow 的 .whl 文件后安装") input("\n按回车返回主菜单...") return folder_queue = [] supported_extensions = {'.jpg', '.jpeg', '.png', '.bmp', '.gif', '.webp', '.tif', '.tiff'} while True: queue_count = len(folder_queue) prompt = f"[{queue_count} 个文件夹待处理] >>> 请输入文件夹路径: " folder_path = input(prompt).strip() if folder_path.lower() == ':y': if not folder_queue: print("警告:队列为空,没有什么可处理的。") print("-" * 30) continue print(f"\n开始执行图片镜像处理,共 {len(folder_queue)} 个文件夹...") for folder in folder_queue: print(f"\n处理文件夹: {folder}") if not os.path.exists(folder): print(f" [警告] 文件夹不存在,跳过") continue if not os.path.isdir(folder): print(f" [警告] 路径不是文件夹,跳过") continue image_count = 0 error_count = 0 for filename in os.listdir(folder): file_path = os.path.join(folder, filename) if not os.path.isfile(file_path): continue _, ext = os.path.splitext(filename) if ext.lower() not in supported_extensions: continue try: if ext.lower() in ['.tif', '.tiff']: with open(file_path, 'rb') as f: img_data = f.read() img = Image.open(BytesIO(img_data)) flipped_img = img.transpose(Image.FLIP_LEFT_RIGHT) output = BytesIO() flipped_img.save(output, format='TIFF') with open(file_path, 'wb') as f: f.write(output.getvalue()) else: img = Image.open(file_path) flipped_img = img.transpose(Image.FLIP_LEFT_RIGHT) flipped_img.save(file_path) print(f" [OK] {filename}") image_count += 1 except Exception as e: print(f" [ERR] {filename} | 原因: {e}") error_count += 1 print(f" 文件夹处理完毕。成功: {image_count}, 失败: {error_count}") print(f"\n全部执行完毕!共处理 {len(folder_queue)} 个文件夹。") print("-" * 30) folder_queue.clear() continue if folder_path.lower() == ':back': if folder_queue: confirm = input(f"队列中还有 {len(folder_queue)} 个文件夹未处理,确定要返回吗?(y/n): ") if confirm.lower() != 'y': continue return if not folder_path: continue folder_queue.append(folder_path) print(f"已加入队列: '{folder_path}'") print("-" * 20) def print_main_menu(): print("\n" + "="*60) print(" 集成工具箱 by FlandreScarle7") print("="*60) print("可用模式:") print(" :mode wb - 文件夹批处理工具 (复制、重命名、标记)") print(" :mode path - 文件夹批量创建工具") print(" :mode photo - 图片左右镜像工具") print(" :exit - 退出程序") print("="*60) def main(): print_main_menu() while True: command = input("\n>>> 请输入命令: ").strip().lower() if command == ":exit": print("[系统] 程序已退出。") sys.exit(0) elif command == ":mode wb": mode_wb() print_main_menu() elif command == ":mode path": mode_path() print_main_menu() elif command == ":mode photo": mode_photo() print_main_menu() elif command == ":help": print_main_menu() else: print("[错误] 未知命令。请输入 :mode wb / :mode path / :mode photo / :exit") if __name__ == "__main__": try: main() except KeyboardInterrupt: print("\n\n[系统] 程序被强制中断。") sys.exit(0)