使用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

相关推荐
开源技术12 分钟前
Python Pillow 优化,打开和保存速度最快提高14倍
开发语言·python·pillow
Li emily1 小时前
解决港股实时行情数据 API 接入难题
人工智能·python·fastapi
wfeqhfxz25887821 小时前
农田杂草检测与识别系统基于YOLO11实现六种杂草自动识别_1
python
mftang2 小时前
Python 字符串拼接成字节详解
开发语言·python
0思必得02 小时前
[Web自动化] Selenium设置相关执行文件路径
前端·爬虫·python·selenium·自动化
石去皿2 小时前
大模型面试通关指南:28道高频考题深度解析与实战要点
人工智能·python·面试·职场和发展
jasligea2 小时前
构建个人智能助手
开发语言·python·自然语言处理
测试秃头怪2 小时前
面试大厂就靠这份软件测试八股文了【含答案】
自动化测试·软件测试·python·功能测试·面试·职场和发展·单元测试
测试杂货铺2 小时前
软件测试面试题大全,你要的都在这。。
自动化测试·软件测试·python·功能测试·面试·职场和发展·测试用例
测试大圣2 小时前
软件测试基础知识总结(超全的)
软件测试·python·功能测试·测试工具·职场和发展·单元测试·测试用例