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

相关推荐
m0_748554811 天前
golang如何实现用户订阅偏好管理_golang用户订阅偏好管理实现总结
jvm·数据库·python
smj2302_796826521 天前
解决leetcode第3911题.移除子数组元素后第k小偶数
数据结构·python·算法·leetcode
阿正呀1 天前
Redis怎样实现本地缓存的高效失效通知
jvm·数据库·python
2501_901200531 天前
mysql如何设置InnoDB引擎参数_优化innodb_buffer_pool
jvm·数据库·python
_.Switch1 天前
东方财富股票数据JS逆向:secids字段和AES加密实战
开发语言·前端·javascript·网络·爬虫·python·ecmascript
Mr_sst1 天前
Claude Code 部署与使用保姆级教程(2026 最新)
python·ai
瞎某某Blinder1 天前
DFT学习记录[6]基于 HES06的能带计算+有效质量计算
python·学习·程序人生·数据挖掘·云计算·学习方法
m0_495496411 天前
mysql处理复杂SQL性能_InnoDB优化器与MyISAM差异
jvm·数据库·python
forEverPlume1 天前
PHP怎么使用Eloquent Attribute Composition属性组合_Laravel通过组合构建复杂属性【方法】
jvm·数据库·python
Aleeeeex1 天前
RAG 那点事:从 8 份企业文档到能用的问答系统,全过程拆给你看
人工智能·python·ai编程