from ftplib import FTP import os import time class FTPManager: def __init__(self, siteFTP, userFTP, passwordFTP, postFTP): self.server = siteFTP self.user = userFTP self.password = passwordFTP self.port = postFTP # Puerto por defecto: 21 self.ftp_client = None self.list_failed_uploads = [] #def __init__(self, **kwargs): # self.server = kwargs.get('server') # self.user = kwargs.get('user') # self.password = kwargs.get('password') # self.port = kwargs.get('port', 21) # Puerto por defecto: 21 # self.ftp_client = None # self.list_failed_uploads = [] def connect(self): """Conecta al servidor FTP""" try: self.ftp_client = FTP() self.ftp_client.connect(self.server, self.port) self.ftp_client.login(self.user, self.password) self.ftp_client.encoding = 'latin-1' #print(f"Conexión exitosa al servidor FTP: {self.server}") except Exception as e: #print(f"Error al conectar al servidor FTP: {e}") raise def disconnect(self): """Cierra la conexión FTP""" if self.ftp_client: self.ftp_client.quit() #print("Conexión cerrada con éxito") def upload_photos(self, local_folder, remote_folder, batch_size=100): """ Sube archivos en lotes de 100. Si hay un error, omite el archivo y lo guarda para intentarlo al final. """ try: self.ftp_client.cwd(remote_folder) except: # if not exit create folder self.ftp_client.mkd(remote_folder) self.ftp_client.cwd(remote_folder) files = [f for f in os.listdir(local_folder) if os.path.isfile(os.path.join(local_folder, f))] total_files = len(files) print(f"Total de archivos a subir: {total_files}") for i in range(0, total_files, batch_size): batch = files[i:i+batch_size] print(f"Subiendo lote {i//batch_size + 1}: {len(batch)} archivos") for file in batch: local_path = os.path.join(local_folder, file) try: with open(local_path, 'rb') as local_file: self.ftp_client.storbinary(f"STOR {file}", local_file) print(f"Subido: {file}") except Exception as e: print(f"Error al subir {file}: {e}") self.list_failed_uploads.append(file) time.sleep(2) # Pequeña pausa entre lotes para estabilidad # Intentar subir nuevamente los fallidos if self.list_failed_uploads: print("Reintentando archivos fallidos...") for file in self.list_failed_uploads: local_path = os.path.join(local_folder, file) try: with open(local_path, 'rb') as local_file: self.ftp_client.storbinary(f"STOR {file}", local_file) print(f"Subido en reintento: {file}") except Exception as e: print(f"Fallo definitivo en {file}: {e}") print("Proceso de subida finalizado.") def uploadFile(self, remote_folder, local_file_path): self.connect() try: self.ftp_client.cwd("/") # 👈 IMPORTANTE self.ensure_remote_path(remote_folder) with open(local_file_path, "rb") as f: file_name = os.path.basename(local_file_path) self.ftp_client.storbinary(f"STOR {file_name}", f) finally: self.disconnect() def ensure_remote_path(self, remote_folder): folders = remote_folder.strip("/").split("/") # SIEMPRE empezar desde raíz self.ftp_client.cwd("/") for folder in folders: if folder == "": continue try: self.ftp_client.cwd(folder) except: self.ftp_client.mkd(folder) #print(f"Creando/navegando carpeta: {folder}") self.ftp_client.cwd(folder) # Ejemplo de uso if __name__ == "__main__": config = { "server": "glmservice.com", "user": "ftpeleaderuser", "password": "AdAw#BaAjwQdc4B", "port": 21 } ftp_manager = FTPManager(**config) try: ftp_manager.connect() ftp_manager.upload_photos("C:\\Users\\emili\\Downloads\\sfotos", "/imglm/test/glmpg01/") finally: ftp_manager.disconnect()