使用python复制目录以及目录的子目录的文件到脚本运行的目录(工具+源码)

目录

不带ui界面的

整体思路

带ui界面的

整体思路

指定目录的复制

小工具下载地址


不带ui界面的

python 复制代码
import 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("📚 所有指定目录的文件复制完成!")

整体思路

  1. 遍历目录以及子目录的文件
复制代码
获取源目录的名称
复制代码
创建存放结果目标文件夹(不存在则创建)
  1. 将遍历的文件复制到脚本运行目录

带ui界面的

python 复制代码
import 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界面
  1. 添加目录按钮
    1. 本质就是在

      复制代码
      self.selected_dirs = []
    2. 这个数组后面添加目录的路径

  2. 清空列表按钮
    1. 本质就是在

      复制代码
      self.selected_dirs = []
    2. 清空这个数组列表

  3. 开始复制按钮
    1. 执行函数

      复制代码
      start_copy()
    2. 这个函数 使用 自身的属性

      1. self.selected_dirs
      2. 进行遍历
      3. 遍历目录以及子目录的文件
      复制代码
      获取源目录的名称
      复制代码
      创建存放结果目标文件夹(不存在则创建)
      1. 将遍历的文件复制到脚本运行目录
  4. 图形界面的 日志ui控件
    1. 这个东西的本质就是
      1. 每次执行的日志信息,在其控件已有的文本内容追加 日志

指定目录的复制

python 复制代码
import 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

相关推荐
前端精髓5 小时前
结构化输出with_structured_output(抽卡)
python·langchain
尹人入圣6 小时前
目前热门的IP驱动产业新场景新工具
网络·python·网络协议·tcp/ip
Nuanyt7 小时前
Agent 学习笔记(下篇三):上线工程、进阶选择与操作界面(Stage 7 / 7.5 / 8 + 延伸路线)
笔记·python·学习·memory·aiagent·harness
吴卫斌7 小时前
定投ETF实战指南(四):行业/主题ETF——定投的“进攻端“
开发语言·python·股票·量化
2601_967987377 小时前
Python——入门级(定义功能def函数)
python·函数·可变参数·默认参数·关键字参数
专注仿真9 小时前
梯度提升类(XFBoost)算法详解与代码实例
开发语言·人工智能·python·算法·大模型训练·控制算法
外收内放9 小时前
Python基础语法练习题(75)
开发语言·python·学习
黑十11 小时前
PyTorch 报 “no CUDA GPUs are available“ 怎么办?3 步排查
服务器·网络·人工智能·pytorch·python
threelab11 小时前
开源图片去水印代码
python
taller_200012 小时前
【012】数据类型入门: Excel 数据到 Python 值的转换
python·excel·pie·py