import os import sys import shutil import threading from pathlib import Path from tkinter import * from tkinter import ttk, filedialog, messagebox, scrolledtext class FileSearchCopyApp: def __init__(self, root): self.root = root self.root.title("文件搜索复制工具") self.root.geometry("900x700") # 设置样式 style = ttk.Style() style.theme_use('clam') # 主框架 main_frame = ttk.Frame(root, padding="10") main_frame.grid(row=0, column=0, sticky=(W, E, N, S)) # 搜索目录选择 ttk.Label(main_frame, text="搜索目录:").grid(row=0, column=0, sticky=W, pady=5) self.search_dir = StringVar() ttk.Entry(main_frame, textvariable=self.search_dir, width=70).grid(row=0, column=1, padx=5, pady=5) ttk.Button(main_frame, text="浏览", command=self.select_search_dir).grid(row=0, column=2, padx=5, pady=5) # 输出目录选择 ttk.Label(main_frame, text="输出目录:").grid(row=1, column=0, sticky=W, pady=5) self.output_dir = StringVar() ttk.Entry(main_frame, textvariable=self.output_dir, width=70).grid(row=1, column=1, padx=5, pady=5) ttk.Button(main_frame, text="浏览", command=self.select_output_dir).grid(row=1, column=2, padx=5, pady=5) # 数据输入区域 ttk.Label(main_frame, text="数据输入(每行一条记录,格式见示例):").grid(row=2, column=0, columnspan=3, sticky=W, pady=5) self.text_area = scrolledtext.ScrolledText(main_frame, height=15, width=100) self.text_area.grid(row=3, column=0, columnspan=3, pady=5) # 添加示例数据按钮 ttk.Button(main_frame, text="加载示例数据", command=self.load_example).grid(row=4, column=0, sticky=W, pady=5) # 启动按钮 self.start_button = ttk.Button(main_frame, text="启动搜索复制", command=self.start_process, width=20) self.start_button.grid(row=4, column=1, pady=10) # 进度条 self.progress = ttk.Progressbar(main_frame, mode='indeterminate') self.progress.grid(row=5, column=0, columnspan=3, sticky=(W, E), pady=5) # 日志输出区域 ttk.Label(main_frame, text="运行日志:").grid(row=6, column=0, columnspan=3, sticky=W, pady=5) self.log_area = scrolledtext.ScrolledText(main_frame, height=15, width=100, fg='blue') self.log_area.grid(row=7, column=0, columnspan=3, pady=5) # 配置网格权重 root.columnconfigure(0, weight=1) root.rowconfigure(0, weight=1) main_frame.columnconfigure(1, weight=1) main_frame.rowconfigure(3, weight=1) main_frame.rowconfigure(7, weight=1) def select_search_dir(self): directory = filedialog.askdirectory() if directory: self.search_dir.set(directory) def select_output_dir(self): directory = filedialog.askdirectory() if directory: self.output_dir.set(directory) def load_example(self): example_data = """POCY2605240030791S01,POCY2605240060314S01 JIT SC202605250059 1 待送仓 代发临时仓 抖音-淘米 2026-05-25 18:00:00 顺丰大网 LOG20260525039490 6 SF5196563054023 2026-05-25 15:47:39 2026-05-25 08:15:39 LOGSUB20260525028998 S花都仓[#]广州花都京东4号仓1楼 平台物流 2 2 2604233548[双面绒毛巾+圆网袋](1);2605253660[双面绒浴巾80*130cm+圆形网兜](1); POCY2605250123665S01,POCY2605250122709S01,POCY2605250123515S01,POCY2605250131779S01,POCY2605250138595S01 JIT SC202605250056 1 待送仓 极点纺织 抖音-淘米 2026-05-25 19:00:00 顺丰大网 LOG20260525032407 6 SF5196563053417 2026-05-25 14:46:29 2026-05-26 13:04:56 LOGSUB20260525024113 S花都仓[#]广州花都京东4号仓1楼 平台物流 6 5 2503131272[70*140深浅条纹浴巾5条装](2);2505241490[6件套(2细浴+1深浅浴+2细毛+1深浅毛)](1);2505241491[6件套(1细浴+2深浅浴+2细毛+1深浅毛)](1);2503131275[70*140深浅条纹浴巾5条装](1);2503131273[70*140深浅条纹浴巾5条装](1); POCY2605250139110S01 JIT SC202605250046 1 待送仓 代发临时仓 抖音-沐居 2026-05-25 19:00:00 跨越速运 LOG20260525027759 6 KYE500152552118-1-1- 2026-05-25 14:18:44 2026-05-26 13:13:44 LOGSUB20260525020896 S花都仓[#]广州花都京东4号仓1楼 平台物流 1 1 2604153514[树叶擦手巾2条装](1); POCY2605250121485S01,POCY2605250129690S01,POCY2605250119171S01,POCY2605250121966S01,POCY2605250131590S01,POCY2605250139769S01,POCY2605250139364S01,POCY2605250136957S01,POCY2605250012046S01 JIT SC202605250045 1 待送仓 晋州工厂 抖音-沐居 2026-05-25 19:00:00 跨越速运 LOG20260525027747 6 KYE500152532118-1-1- 2026-05-25 14:18:44 2026-05-26 08:06:03 LOGSUB20260525020890 S花都仓[#]广州花都京东4号仓1楼 平台物流 11 9 240925439[印花宠物毛巾4条装](1);2508151793[男士大尺寸浴裙 麦穗款](1);241022640[豁口毛巾2条装](2);2605073595[35*75cm宠物绣花毛巾 4条装](1);HDJYQ015[蝴蝶结浴裙80*165cm](1);2508151794[男士大尺寸浴裙 欧花款](2);240829219[珊瑚绒印花小毛巾](1);DCBLGGFM04[单层菠萝格干发帽 小熊扣](1);2603213399[雪尼尔鞋套2条装](1); POCY2605250105996S01 SC202605250044 1 待送仓 晋州工厂 抖音-沐居 2026-05-25 19:00:00 跨越速运 LOG20260525027739 6 KYE500152041019-1-1- 2026-05-25 14:18:44 2026-05-28 00:00:00 LOGSUB20260525020886 S花都仓[#]广州花都京东4号仓1楼 平台物流 24 1 2505301510[60*90小辫子擦车巾600gsm单层](24);""" self.text_area.delete(1.0, END) self.text_area.insert(1.0, example_data) def log_message(self, message, is_error=False): """在日志区域显示消息""" self.log_area.insert(END, f"{message}\n") self.log_area.see(END) if is_error: # 可以添加错误计数或其他处理 pass def search_files(self, search_dir, order_number): """在搜索目录中搜索包含订单号的文件""" found_files = [] search_path = Path(search_dir) try: # 遍历所有文件 for file_path in search_path.rglob('*'): if file_path.is_file() and order_number in file_path.name: found_files.append(file_path) except Exception as e: self.log_message(f"搜索 {order_number} 时出错: {str(e)}", True) return found_files def copy_files(self, files, output_dir, order_number): """复制文件到目标目录""" # 创建订单号目录 target_dir = Path(output_dir) / order_number target_dir.mkdir(parents=True, exist_ok=True) copied_count = 0 for file_path in files: try: # 构建目标文件路径 target_file = target_dir / file_path.name # 如果文件已存在,添加序号 if target_file.exists(): base_name = file_path.stem extension = file_path.suffix counter = 1 while target_file.exists(): new_name = f"{base_name}_{counter}{extension}" target_file = target_dir / new_name counter += 1 # 复制文件 shutil.copy2(file_path, target_file) copied_count += 1 self.log_message(f" 已复制: {file_path.name} -> {target_file}") except Exception as e: self.log_message(f" 复制失败 {file_path.name}: {str(e)}", True) return copied_count def process_data(self): """处理数据的主函数""" search_dir = self.search_dir.get() output_dir = self.output_dir.get() data_text = self.text_area.get(1.0, END).strip() # 验证输入 if not search_dir: self.log_message("错误:请选择搜索目录!", True) return False if not output_dir: self.log_message("错误:请选择输出目录!", True) return False if not data_text: self.log_message("错误:请在数据输入框中输入数据!", True) return False if not os.path.exists(search_dir): self.log_message(f"错误:搜索目录不存在! {search_dir}", True) return False if not os.path.exists(output_dir): self.log_message(f"错误:输出目录不存在! {output_dir}", True) return False # 解析数据,提取订单号 lines = data_text.split('\n') order_numbers = set() # 使用set去重 for line_num, line in enumerate(lines, 1): if not line.strip(): continue # 按制表符分割 parts = line.split('\t') if len(parts) >= 3: order_number = parts[2].strip() if order_number: order_numbers.add(order_number) self.log_message(f"提取订单号: {order_number}") else: self.log_message(f"警告:第{line_num}行订单号为空") else: self.log_message(f"警告:第{line_num}行格式不正确,字段数不足3个") if not order_numbers: self.log_message("错误:未能提取到有效的订单号!", True) return False self.log_message(f"\n共提取到 {len(order_numbers)} 个订单号") self.log_message("=" * 60) # 处理每个订单号 total_files_copied = 0 processed_orders = 0 for order_number in order_numbers: self.log_message(f"\n处理订单号: {order_number}") self.log_message(f"搜索目录: {search_dir}") # 搜索文件 found_files = self.search_files(search_dir, order_number) if found_files: self.log_message(f"找到 {len(found_files)} 个相关文件:") for file_path in found_files: self.log_message(f" - {file_path.relative_to(search_dir)}") # 复制文件 copied_count = self.copy_files(found_files, output_dir, order_number) total_files_copied += copied_count self.log_message(f"成功复制 {copied_count} 个文件到 {output_dir}/{order_number}") processed_orders += 1 else: self.log_message(f"警告:未找到包含 {order_number} 的文件", True) self.log_message("\n" + "=" * 60) self.log_message(f"处理完成!") self.log_message(f"成功处理订单数: {processed_orders}/{len(order_numbers)}") self.log_message(f"共复制文件数: {total_files_copied}") return True def run_in_thread(self): """在新线程中运行处理程序""" self.start_button.config(state=DISABLED) self.progress.start() try: success = self.process_data() if success: messagebox.showinfo("完成", "文件搜索复制完成!") else: messagebox.showerror("错误", "处理过程中出现错误,请查看日志。") except Exception as e: self.log_message(f"程序运行错误: {str(e)}", True) messagebox.showerror("错误", f"程序运行错误: {str(e)}") finally: self.progress.stop() self.start_button.config(state=NORMAL) def start_process(self): """启动处理程序""" # 在新线程中运行,避免界面卡顿 thread = threading.Thread(target=self.run_in_thread) thread.daemon = True thread.start() def main(): root = Tk() app = FileSearchCopyApp(root) root.mainloop() if __name__ == "__main__": main()