From e8369886b0d6e82ae9ad54407a75827335dc665a Mon Sep 17 00:00:00 2001 From: godax84 Date: Mon, 2 Jun 2025 10:58:10 +0000 Subject: [PATCH] Modificar ecu_ascii_analyzer.py --- ecu_ascii_analyzer.py | 134 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 133 insertions(+), 1 deletion(-) diff --git a/ecu_ascii_analyzer.py b/ecu_ascii_analyzer.py index 0f5460b..496c8d6 100644 --- a/ecu_ascii_analyzer.py +++ b/ecu_ascii_analyzer.py @@ -2,6 +2,8 @@ import tkinter as tk from tkinter import filedialog, scrolledtext, ttk, messagebox import re import os +import shutil # Nova importação para operações de ficheiro (cópia) +from datetime import datetime # Nova importação para timestamp from collections import Counter # Importações dos novos módulos de padrões @@ -16,6 +18,13 @@ from Data.bmw_ecu_group_handler import load_bmw_ecu_list # Nova importação par # from patterns.bmw_patterns import PATTERNS_BMW # etc. +def sanitize_name(name): + """Remove caracteres inválidos de uma string para usar como nome de ficheiro/pasta.""" + # Remove ou substitui caracteres que são tipicamente problemáticos em nomes de ficheiro/pasta + name = re.sub(r'[\/*?"<>|:]', '_', name) + name = name.replace('\n', '_').replace('\r', '_') + return name[:100] # Limita o comprimento para evitar nomes excessivamente longos + # --- Constantes Globais --- BRAND_NAMES = ['VAG', 'LandRover/Jaguar', 'BMW', 'Mercedes', 'Renault/Dacia', 'Peugeot/Citroen', 'Opel', 'Fiat/Lancia/Alfa', 'Ford'] @@ -496,9 +505,13 @@ def create_main_window(): global_progress_label = progress_label brand_buttons_frame = ttk.Frame(root) - brand_buttons_frame.pack(pady=5, padx=10, fill=tk.X) + brand_buttons_frame.pack(pady=5, padx=5, fill=tk.X) global_brand_buttons_frame = brand_buttons_frame + # Botão Global File Organizer + file_organizer_button = ttk.Button(root, text="File Organizer", command=initiate_bmw_file_organizer) + file_organizer_button.pack(pady=5, padx=10, fill=tk.X) + category_buttons_frame = ttk.Frame(root) category_buttons_frame.pack(pady=5, padx=10, fill=tk.X) global_category_buttons_frame = category_buttons_frame @@ -510,5 +523,124 @@ def create_main_window(): clear_ui_state() # Limpa a UI antes de iniciar root.mainloop() +def process_folder_for_bmw_organization(source_folder, base_destination_folder, progress_callback=None): + """Processa uma pasta, analisa ficheiros BMW e organiza-os em subpastas nomeadas.""" + processed_files = 0 + failed_files = 0 + total_files = sum([len(files) for r, d, files in os.walk(source_folder)]) + current_file_count = 0 + + if progress_callback: + progress_callback(0, total_files, "Iniciando organização...") + + for root, _, files in os.walk(source_folder): + for filename in files: + current_file_count += 1 + if progress_callback: + progress_callback(current_file_count, total_files, f"Processando: {filename}") + + file_path = os.path.join(root, filename) + try: + ascii_content = read_file_content(file_path) + if not ascii_content: + print(f"Não foi possível ler o conteúdo ASCII de: {filename}") + failed_files += 1 + continue + + # Realiza uma análise inicial para 'Ecu Family' e 'Possible Software Number' + initial_patterns = {key: PATTERNS_COMMON[key] for key in INITIAL_ANALYSIS_PATTERNS_KEYS if key in PATTERNS_COMMON} + analysis_results = analyze_ascii_patterns_from_file(ascii_content, initial_patterns) + + ecu_family_data = analysis_results.get('Ecu Family', {}) + sw_number_data = analysis_results.get('Possible Software Number', {}) + + # Pega o primeiro (ou mais comum) Ecu Family e Software Number + # Pode ser necessário refinar esta lógica para escolher o "melhor" se houver múltiplos + main_ecu_family = next(iter(ecu_family_data.keys()), "UnknownECU") + main_sw_number = next(iter(sw_number_data.keys()), "UnknownSW") + + # Sanitiza os nomes para criar nomes de pasta válidos + s_ecu_family = sanitize_name(main_ecu_family) + s_sw_number = sanitize_name(main_sw_number) + s_filename = sanitize_name(os.path.splitext(filename)[0]) # Nome do ficheiro sem extensão + + # Cria o nome da pasta da família da ECU + ecu_family_folder_name = s_ecu_family + ecu_family_path = os.path.join(base_destination_folder, ecu_family_folder_name) + os.makedirs(ecu_family_path, exist_ok=True) + + # Cria o nome da subpasta de destino final dentro da pasta da família da ECU + # Ex: BMW_EDC17C41_10SW012345_NomeOriginalDoFicheiro + subfolder_name = f"BMW_{s_ecu_family}_{s_sw_number}_{s_filename}" + destination_subfolder = os.path.join(ecu_family_path, subfolder_name) + + os.makedirs(destination_subfolder, exist_ok=True) + + # Copia o ficheiro original + shutil.copy2(file_path, os.path.join(destination_subfolder, filename)) + + # Cria o ficheiro de texto com os dados recolhidos + info_file_path = os.path.join(destination_subfolder, f"info_{s_filename}.txt") + with open(info_file_path, 'w', encoding='utf-8') as info_f: + info_f.write(f"Ficheiro Original: {filename}\n") + info_f.write(f"Caminho Original: {file_path}\n") + info_f.write(f"Data da Análise: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n") + info_f.write(f"Ecu Family Encontrada: {main_ecu_family}\n") + if ecu_family_data: + for ecu, count in ecu_family_data.items(): + info_f.write(f" - {ecu} (Contagem: {count})\n") + info_f.write(f"\nSoftware Number Encontrado: {main_sw_number}\n") + if sw_number_data: + for sw, count in sw_number_data.items(): + info_f.write(f" - {sw} (Contagem: {count})\n") + # Adicionar mais dados se necessário + + processed_files += 1 + except PermissionError as e_perm: + print(f"Erro de permissão ao processar o ficheiro {filename}: {e_perm}. O ficheiro pode estar em uso.") + failed_files += 1 + except Exception as e: + print(f"Erro geral ao processar o ficheiro {filename}: {e}") + failed_files += 1 + # Considerar logar o erro para um ficheiro de log + + if progress_callback: + progress_callback(total_files, total_files, "Organização concluída!") + + return processed_files, failed_files + +def initiate_bmw_file_organizer(): + source_dir = filedialog.askdirectory(title="Selecione a Pasta de Origem com Ficheiros BMW") + if not source_dir: + messagebox.showinfo("Cancelado", "Operação de organização cancelada.") + return + + dest_dir = filedialog.askdirectory(title="Selecione a Pasta de Destino Base para Organização") + if not dest_dir: + messagebox.showinfo("Cancelado", "Operação de organização cancelada.") + return + + if global_progress_bar and global_progress_label: + def progress_update(current, total, message): + global_progress_label.config(text=message) + if total > 0: + percentage = (current / total) * 100 + global_progress_bar['value'] = percentage + else: + global_progress_bar['value'] = 0 + if global_root_window: global_root_window.update_idletasks() + + try: + processed, failed = process_folder_for_bmw_organization(source_dir, dest_dir, progress_update) + summary_message = f"Organização Concluída.\nFicheiros Processados com Sucesso: {processed}\nFicheiros com Falha: {failed}" + messagebox.showinfo("Concluído", summary_message) + except Exception as e: + messagebox.showerror("Erro na Organização", f"Ocorreu um erro: {e}") + if global_progress_label: global_progress_label.config(text="Erro na organização.") + if global_progress_bar: global_progress_bar['value'] = 0 + else: + messagebox.showerror("Erro", "Componentes de progresso não inicializados.") + + if __name__ == "__main__": create_main_window() \ No newline at end of file