| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- 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()
|