From ee26905bcd1f37119871a7fc646c89b9c6c68e1b Mon Sep 17 00:00:00 2001 From: Luis Rodrigues Date: Fri, 2 May 2025 15:17:17 +0100 Subject: [PATCH] implementar multithreading na copia de ficheiros --- modules/copier.py | 111 ++++++++++++++++++++++++++++++---------------- 1 file changed, 73 insertions(+), 38 deletions(-) diff --git a/modules/copier.py b/modules/copier.py index 9e2e6f1..82459be 100644 --- a/modules/copier.py +++ b/modules/copier.py @@ -8,15 +8,61 @@ from modules.organizer import ( from pathlib import Path import shutil from tqdm import tqdm +from concurrent.futures import ThreadPoolExecutor, as_completed from modules.logger import logger +def copiar_ficheiro_individual( + ficheiro: str, + base_destino: str, + categorizar_data: bool = False, + usar_criacao: bool = False, + formato_data: str = "%Y-%m-%d", +) -> None: + """copiar um ficheiro para o destino indicado, + com base nos parametros passados + + argumentos: + ficheiro (str) -> caminho (como str) do ficheiro a ser copiado + base_destino (str) -> directório de destino para onde será copiado o ficheiro + categorizar_data (bool) -> flag para activar categorização por data (defeito: False) + usar_criacao (bool) -> usar data de criação (defeito: False usar data de modificacao) + formato_data (str) -> formato de data para nome dos subdirectórios (defeito: '%d-%m-%Y') + + retorna: + None + """ + try: + ficheiro_path = Path(ficheiro) + if not ficheiro_path.exists(): + logger.warning("Ficheiro '%s' não encontrado. A ignorar.", ficheiro) + return + if categorizar_data: + data_ficheiro = obter_data_ficheiro(ficheiro, usar_criacao=usar_criacao) + pasta_destino = criar_pasta_destino( + str(base_destino), + categorizar_por_tipo(ficheiro), + data_ficheiro, + formato_data, + ) + else: + pasta_destino = criar_pasta_destino( + str(base_destino), categorizar_por_tipo(ficheiro) + ) + destino_ficheiro = pasta_destino / ficheiro_path.name + shutil.copy2(ficheiro_path, destino_ficheiro) + except Exception as e: + logger.error("Erro a copiar '%s': %s", Path(ficheiro).name, e) + + def copiar_ficheiros_para_destino( lista_ficheiros: list[str], base_destino: str, categorizar_data: bool = False, usar_criacao: bool = False, - formato_data: str = "%d-%m-%Y", + formato_data: str = "%Y-%m-%d", + usar_threads: bool = True, + max_workers: int = 8, ) -> None: """ Copiar cada ficheiro na lista para o directório base, seguindo as regras de categorização @@ -31,42 +77,31 @@ def copiar_ficheiros_para_destino( retorna: None """ - destino_path = Path(base_destino) - with tqdm( - total=len(lista_ficheiros), desc="A copiar ficheiros ", unit="ficheiro " - ) as barra_progresso: - for ficheiro in lista_ficheiros: - ficheiro_path = Path(ficheiro) - try: - if not ficheiro_path.exists(): - logger.warning("Ficheiro '%s' não encontrado. A ignorar.", ficheiro) - barra_progresso.update(1) - continue - - if categorizar_data: - data_ficheiro = obter_data_ficheiro( - ficheiro, usar_criacao=usar_criacao - ) - pasta_destino = criar_pasta_destino( - str(destino_path), - categorizar_por_tipo(ficheiro), - data_ficheiro, - formato_data, - ) - else: - pasta_destino = criar_pasta_destino( - str(destino_path), - categorizar_por_tipo(ficheiro), - ) - - destino_ficheiro = pasta_destino / ficheiro_path.name - shutil.copy2(ficheiro_path, destino_ficheiro) - logger.info( - "Ficheiro '%s' copiado com sucesso para '%s'", + if usar_threads: + with ThreadPoolExecutor(max_workers=max_workers) as executor: + futures = [ + executor.submit( + copiar_ficheiro_individual, ficheiro, - destino_ficheiro, + base_destino, + categorizar_data, + usar_criacao, + formato_data, ) - except Exception as e: - logger.error("Erro a copiar '%s': %s", Path(ficheiro).name, e) - finally: - barra_progresso.update(1) + for ficheiro in lista_ficheiros + ] + + for _ in tqdm( + as_completed(futures), + total=len(futures), + desc="A copiar ficheiros ", + unit="ficheiro ", + ): + pass + else: + for ficheiro in tqdm( + lista_ficheiros, desc="A copiar ficheiros ", unit="ficheiro " + ): + copiar_ficheiro_individual( + ficheiro, base_destino, categorizar_data, usar_criacao, formato_data + )