目录
不带ui界面的
pythonimport os import shutil def copy_files_to_root(target_dirs): """ 将多个指定目录下的所有文件(包括子目录)复制到当前脚本的根目录, 所有文件平铺到以源目录名命名的文件夹中(无嵌套子目录) Args: target_dirs (list): 要复制的源目录路径列表 """ # 获取当前脚本的根目录(即运行该py文件的目录) script_root = os.path.dirname(os.path.abspath(__file__)) print(f"脚本根目录: {script_root}\n") # 遍历每个目标目录 for target_dir in target_dirs: # 检查源目录是否存在 if not os.path.isdir(target_dir): print(f"⚠️ 错误:源目录 {target_dir} 不存在,跳过该目录!") continue # 获取源目录的名称(作为根目录下的目标文件夹名) dir_name = os.path.basename(os.path.normpath(target_dir)) # 最终目标文件夹(脚本根目录 + 源目录名) dest_root = os.path.join(script_root, dir_name) # 创建目标文件夹(不存在则创建) os.makedirs(dest_root, exist_ok=True) print(f"🔄 开始复制目录:{target_dir} -> {dest_root}(所有文件平铺)") # 遍历源目录下的所有文件(包括子目录) for root, dirs, files in os.walk(target_dir): # 复制当前目录下的所有文件(直接放到目标根文件夹) for file in files: # 源文件完整路径 src_file = os.path.join(root, file) # 初始目标文件路径(平铺到目标根文件夹) dest_file = os.path.join(dest_root, file) # 处理重名文件:如果文件已存在,自动添加序号(如 file.txt -> file_1.txt) counter = 1 while os.path.exists(dest_file): file_name, file_ext = os.path.splitext(file) dest_file = os.path.join(dest_root, f"{file_name}_{counter}{file_ext}") counter += 1 # 复制文件 try: shutil.copy2(src_file, dest_file) print(f"✅ 已复制: {src_file} -> {dest_file}") except Exception as e: print(f"❌ 复制失败: {src_file} 原因: {e}") print(f"✅ 目录 {target_dir} 复制完成!\n") if __name__ == "__main__": # 传入多个目录路径的数组(列表) target_directories = [ r"E:\test\a", # 第一个要复制的目录 r"E:\test\b", # 第二个要复制的目录 r"E:\test\c", # 第二个要复制的目录 ] # 执行复制操作 copy_files_to_root(target_directories) print("📚 所有指定目录的文件复制完成!")

整体思路
- 遍历目录以及子目录的文件
获取源目录的名称
创建存放结果目标文件夹(不存在则创建)
- 将遍历的文件复制到脚本运行目录
带ui界面的
pythonimport os import shutil import tkinter as tk from tkinter import ttk, filedialog, messagebox class FileCopyGUI: def __init__(self, root): self.root = root self.root.title("文件批量复制工具") self.root.geometry("700x500") # 窗口大小 # 存储选中的源目录列表 self.selected_dirs = [] # 创建UI组件 self._create_widgets() def _create_widgets(self): # 1. 目录选择区域 frame_select = ttk.LabelFrame(self.root, text="选择要复制的目录") frame_select.pack(padx=10, pady=10, fill=tk.X) # 选择目录按钮 btn_add_dir = ttk.Button(frame_select, text="添加目录", command=self.add_directory) btn_add_dir.pack(side=tk.LEFT, padx=10, pady=5) # 清空目录按钮 btn_clear_dirs = ttk.Button(frame_select, text="清空列表", command=self.clear_directories) btn_clear_dirs.pack(side=tk.LEFT, padx=5, pady=5) # 目录列表展示 self.dir_listbox = tk.Listbox(frame_select, height=8, width=80) self.dir_listbox.pack(side=tk.LEFT, padx=10, pady=5, fill=tk.X, expand=True) # 滚动条 scrollbar = ttk.Scrollbar(frame_select, orient=tk.VERTICAL, command=self.dir_listbox.yview) scrollbar.pack(side=tk.RIGHT, fill=tk.Y, pady=5) self.dir_listbox.config(yscrollcommand=scrollbar.set) # 2. 操作按钮区域 frame_operate = ttk.Frame(self.root) frame_operate.pack(padx=10, pady=5, fill=tk.X) btn_copy = ttk.Button(frame_operate, text="开始复制", command=self.start_copy, style="Accent.TButton") btn_copy.pack(side=tk.LEFT, padx=10, pady=5) # 3. 日志输出区域 frame_log = ttk.LabelFrame(self.root, text="复制日志") frame_log.pack(padx=10, pady=10, fill=tk.BOTH, expand=True) # 日志文本框 self.log_text = tk.Text(frame_log, height=15, wrap=tk.WORD) self.log_text.pack(side=tk.LEFT, padx=10, pady=5, fill=tk.BOTH, expand=True) # 日志滚动条 log_scrollbar = ttk.Scrollbar(frame_log, orient=tk.VERTICAL, command=self.log_text.yview) log_scrollbar.pack(side=tk.RIGHT, fill=tk.Y, pady=5) self.log_text.config(yscrollcommand=log_scrollbar.set) # 设置文本框只读 self.log_text.config(state=tk.DISABLED) def add_directory(self): """添加选中的目录到列表""" dir_path = filedialog.askdirectory(title="选择要复制的目录") if dir_path and dir_path not in self.selected_dirs: self.selected_dirs.append(dir_path) self.dir_listbox.insert(tk.END, dir_path) self._log(f"已添加目录:{dir_path}") def clear_directories(self): """清空选中的目录列表""" self.selected_dirs.clear() self.dir_listbox.delete(0, tk.END) self._log("已清空目录列表") def _log(self, message): """在日志框中输出信息""" self.log_text.config(state=tk.NORMAL) self.log_text.insert(tk.END, f"{message}\n") self.log_text.see(tk.END) # 自动滚动到最后一行 self.log_text.config(state=tk.DISABLED) self.root.update_idletasks() # 实时刷新界面 def start_copy(self): """执行文件复制操作""" if not self.selected_dirs: messagebox.showwarning("警告", "请先添加要复制的目录!") return # 获取脚本根目录 script_root = os.path.dirname(os.path.abspath(__file__)) self._log(f"===== 开始复制 =====") self._log(f"脚本根目录:{script_root}") # 遍历每个选中的目录 for target_dir in self.selected_dirs: if not os.path.isdir(target_dir): self._log(f"⚠️ 错误:目录 {target_dir} 不存在,跳过!") continue # 目标文件夹(脚本根目录/源目录名) dir_name = os.path.basename(os.path.normpath(target_dir)) dest_root = os.path.join(script_root, dir_name) os.makedirs(dest_root, exist_ok=True) self._log(f"\n🔄 处理目录:{target_dir} -> {dest_root}(文件平铺)") # 遍历所有文件并复制 file_count = 0 for root, dirs, files in os.walk(target_dir): for file in files: src_file = os.path.join(root, file) dest_file = os.path.join(dest_root, file) # 处理重名文件 counter = 1 while os.path.exists(dest_file): file_name, ext = os.path.splitext(file) dest_file = os.path.join(dest_root, f"{file_name}_{counter}{ext}") counter += 1 # 复制文件 try: shutil.copy2(src_file, dest_file) self._log(f"✅ 复制成功:{os.path.basename(dest_file)}") file_count += 1 except Exception as e: self._log(f"❌ 复制失败:{src_file} 原因:{str(e)}") self._log(f"✅ 目录 {target_dir} 处理完成,共复制 {file_count} 个文件") self._log(f"\n===== 所有目录处理完成 =====") messagebox.showinfo("完成", "文件复制操作已全部执行完毕!") if __name__ == "__main__": # 创建主窗口 root = tk.Tk() # 设置按钮样式(可选) style = ttk.Style(root) style.configure("Accent.TButton", foreground="white", background="#0078d7") # 启动GUI app = FileCopyGUI(root) root.mainloop()

添加目录

选择结果

开始复制

结果


整体思路
使用python中的tkinter 库,创建ui界面
- 添加目录按钮
-
本质就是在
self.selected_dirs = [] -
这个数组后面添加目录的路径
-
- 清空列表按钮
-
本质就是在
self.selected_dirs = [] -
清空这个数组列表
-
- 开始复制按钮
-
执行函数
start_copy() -
这个函数 使用 自身的属性
- self.selected_dirs
- 进行遍历
- 遍历目录以及子目录的文件
获取源目录的名称创建存放结果目标文件夹(不存在则创建)- 将遍历的文件复制到脚本运行目录
-
- 图形界面的 日志ui控件
- 这个东西的本质就是
- 每次执行的日志信息,在其控件已有的文本内容追加 日志
- 这个东西的本质就是
指定目录的复制

pythonimport os import shutil import tkinter as tk from tkinter import ttk, filedialog, messagebox class FileCopyGUI: def __init__(self, root): self.root = root self.root.title("文件批量复制工具") self.root.geometry("700x550") # 窗口大小略微调整 # 存储选中的源目录列表和目标输出目录 self.selected_dirs = [] self.output_dir = "" # 新增:存储用户指定的输出目录 # 创建UI组件 self._create_widgets() def _create_widgets(self): # 1. 目录选择区域(源目录) frame_select = ttk.LabelFrame(self.root, text="选择要复制的源目录") frame_select.pack(padx=10, pady=10, fill=tk.X) # 选择目录按钮 btn_add_dir = ttk.Button(frame_select, text="添加目录", command=self.add_directory) btn_add_dir.pack(side=tk.LEFT, padx=10, pady=5) # 清空目录按钮 btn_clear_dirs = ttk.Button(frame_select, text="清空列表", command=self.clear_directories) btn_clear_dirs.pack(side=tk.LEFT, padx=5, pady=5) # 目录列表展示 self.dir_listbox = tk.Listbox(frame_select, height=8, width=80) self.dir_listbox.pack(side=tk.LEFT, padx=10, pady=5, fill=tk.X, expand=True) # 滚动条 scrollbar = ttk.Scrollbar(frame_select, orient=tk.VERTICAL, command=self.dir_listbox.yview) scrollbar.pack(side=tk.RIGHT, fill=tk.Y, pady=5) self.dir_listbox.config(yscrollcommand=scrollbar.set) # ========== 新增:目标输出目录选择区域 ========== frame_output = ttk.LabelFrame(self.root, text="选择文件输出目录") frame_output.pack(padx=10, pady=5, fill=tk.X) # 显示当前选中的输出目录 self.output_dir_var = tk.StringVar(value="未选择输出目录") lbl_output = ttk.Label(frame_output, textvariable=self.output_dir_var) lbl_output.pack(side=tk.LEFT, padx=10, pady=5, fill=tk.X, expand=True) # 选择输出目录按钮 btn_select_output = ttk.Button(frame_output, text="选择目录", command=self.select_output_directory) btn_select_output.pack(side=tk.LEFT, padx=10, pady=5) # ============================================= # 2. 操作按钮区域 frame_operate = ttk.Frame(self.root) frame_operate.pack(padx=10, pady=5, fill=tk.X) btn_copy = ttk.Button(frame_operate, text="开始复制", command=self.start_copy, style="Accent.TButton") btn_copy.pack(side=tk.LEFT, padx=10, pady=5) # 3. 日志输出区域 frame_log = ttk.LabelFrame(self.root, text="复制日志") frame_log.pack(padx=10, pady=10, fill=tk.BOTH, expand=True) # 日志文本框 self.log_text = tk.Text(frame_log, height=15, wrap=tk.WORD) self.log_text.pack(side=tk.LEFT, padx=10, pady=5, fill=tk.BOTH, expand=True) # 日志滚动条 log_scrollbar = ttk.Scrollbar(frame_log, orient=tk.VERTICAL, command=self.log_text.yview) log_scrollbar.pack(side=tk.RIGHT, fill=tk.Y, pady=5) self.log_text.config(yscrollcommand=log_scrollbar.set) # 设置文本框只读 self.log_text.config(state=tk.DISABLED) def add_directory(self): """添加选中的目录到列表""" dir_path = filedialog.askdirectory(title="选择要复制的目录") if dir_path and dir_path not in self.selected_dirs: self.selected_dirs.append(dir_path) self.dir_listbox.insert(tk.END, dir_path) self._log(f"已添加目录:{dir_path}") def clear_directories(self): """清空选中的目录列表""" self.selected_dirs.clear() self.dir_listbox.delete(0, tk.END) self._log("已清空目录列表") # ========== 新增:选择输出目录的方法 ========== def select_output_directory(self): """让用户选择文件复制后的输出目录""" dir_path = filedialog.askdirectory(title="选择文件输出目录") if dir_path: self.output_dir = dir_path self.output_dir_var.set(f"当前输出目录:{dir_path}") self._log(f"已选择输出目录:{dir_path}") # ============================================= def _log(self, message): """在日志框中输出信息""" self.log_text.config(state=tk.NORMAL) self.log_text.insert(tk.END, f"{message}\n") self.log_text.see(tk.END) # 自动滚动到最后一行 self.log_text.config(state=tk.DISABLED) self.root.update_idletasks() # 实时刷新界面 def start_copy(self): """执行文件复制操作""" # 新增:检查输出目录是否选择 if not self.output_dir: messagebox.showwarning("警告", "请先选择文件输出目录!") return if not self.selected_dirs: messagebox.showwarning("警告", "请先添加要复制的目录!") return self._log(f"===== 开始复制 =====") self._log(f"输出根目录:{self.output_dir}") # 遍历每个选中的目录 for target_dir in self.selected_dirs: if not os.path.isdir(target_dir): self._log(f"⚠️ 错误:目录 {target_dir} 不存在,跳过!") continue # 修改:目标文件夹改为【用户指定的输出目录/源目录名】 dir_name = os.path.basename(os.path.normpath(target_dir)) dest_root = os.path.join(self.output_dir, dir_name) # 核心修改点 os.makedirs(dest_root, exist_ok=True) self._log(f"\n🔄 处理目录:{target_dir} -> {dest_root}(文件平铺)") # 遍历所有文件并复制 file_count = 0 for root, dirs, files in os.walk(target_dir): for file in files: src_file = os.path.join(root, file) dest_file = os.path.join(dest_root, file) # 处理重名文件 counter = 1 while os.path.exists(dest_file): file_name, ext = os.path.splitext(file) dest_file = os.path.join(dest_root, f"{file_name}_{counter}{ext}") counter += 1 # 复制文件 try: shutil.copy2(src_file, dest_file) self._log(f"✅ 复制成功:{os.path.basename(dest_file)}") file_count += 1 except Exception as e: self._log(f"❌ 复制失败:{src_file} 原因:{str(e)}") self._log(f"✅ 目录 {target_dir} 处理完成,共复制 {file_count} 个文件") self._log(f"\n===== 所有目录处理完成 =====") messagebox.showinfo("完成", "文件复制操作已全部执行完毕!") if __name__ == "__main__": # 创建主窗口 root = tk.Tk() # 设置按钮样式(可选) style = ttk.Style(root) style.configure("Accent.TButton", foreground="white", background="#0078d7") # 启动GUI app = FileCopyGUI(root) root.mainloop()
小工具下载地址
https://www.123865.com/s/lWZKVv-Zt6av?pwd=gyy0#
提取码:gyy0

压缩密码:xiji