@@ -203,16 +203,61 @@ def criar_pasta(self, pasta_pai: Folder | str, nome_pasta: str):
203
203
pasta .execute_query ()
204
204
return pasta
205
205
206
- @handle_sharepoint_errors ()
207
- def baixar_arquivo (self , arquivo_sp : File | str , caminho_download : str ):
208
- """Baixa um arquivo do SharePoint para um caminho local."""
206
+ def baixar_arquivo (self , arquivo_sp : File | str , caminho_download : str , max_tentativas : int = 3 ):
207
+ """
208
+ Baixa um arquivo do SharePoint para um caminho local, com verificação de integridade e novas tentativas.
209
+ """
209
210
if isinstance (arquivo_sp , str ):
210
- file_to_download = self .ctx .web .get_file_by_server_relative_url (arquivo_sp )
211
+ file_to_download = self .obter_arquivo (arquivo_sp )
212
+ if file_to_download is None :
213
+ raise FileNotFoundError (f"Arquivo remoto '{ arquivo_sp } ' não encontrado." )
211
214
else :
212
215
file_to_download = arquivo_sp
216
+ # Garante que os metadados do arquivo (como o tamanho) estão carregados
217
+ file_to_download .get ().execute_query ()
218
+
219
+ # O decorador @handle_sharepoint_errors em obter_arquivo já tratou erros de API aqui.
220
+ tamanho_remoto = file_to_download .length
221
+
222
+ for tentativa in range (max_tentativas ):
223
+ print (f"Iniciando download de '{ file_to_download .name } ' (Tentativa { tentativa + 1 } /{ max_tentativas } )..." )
224
+
225
+ try :
226
+ with open (caminho_download , "wb" ) as local_file :
227
+ file_to_download .download_session (local_file ).execute_query ()
228
+
229
+ # Verificação do tamanho do arquivo
230
+ tamanho_local = os .path .getsize (caminho_download )
231
+
232
+ if tamanho_local == tamanho_remoto :
233
+ print (
234
+ f"Download de '{ file_to_download .name } ' concluído e verificado com sucesso. Tamanho: { tamanho_local } bytes." )
235
+ return # Sucesso, sai da função
236
+ else :
237
+ print (f"Falha na verificação de tamanho para '{ file_to_download .name } '." )
238
+ print (f" -> Tamanho esperado: { tamanho_remoto } bytes" )
239
+ print (f" -> Tamanho baixado: { tamanho_local } bytes" )
240
+
241
+ except Exception as e :
242
+ print (f"Ocorreu um erro durante o download na tentativa { tentativa + 1 } /{ max_tentativas } : { e } " )
243
+
244
+ if tentativa < max_tentativas - 1 :
245
+ print ("Aguardando 5 segundos para tentar novamente..." )
246
+ time .sleep (5 )
247
+
248
+ # Se o loop terminar, todas as tentativas falharam.
249
+ print (f"Falha ao baixar o arquivo '{ file_to_download .name } ' após { max_tentativas } tentativas." )
250
+
251
+ # Tenta remover o arquivo parcial/corrompido
252
+ try :
253
+ if os .path .exists (caminho_download ):
254
+ os .remove (caminho_download )
255
+ print (f"Arquivo parcial '{ caminho_download } ' removido." )
256
+ except OSError as e :
257
+ print (f"Não foi possível remover o arquivo parcial '{ caminho_download } ': { e } " )
213
258
214
- with open ( caminho_download , "wb" ) as local_file :
215
- file_to_download .download_session ( local_file ). execute_query ( )
259
+ raise IOError (
260
+ f"Não foi possível baixar o arquivo ' { file_to_download .name } ' com o tamanho correto após { max_tentativas } tentativas." )
216
261
217
262
@handle_sharepoint_errors ()
218
263
def enviar_arquivo (self , pasta_destino : Folder | str , arquivo_local : str , nome_arquivo_sp : str = None ):
@@ -279,4 +324,4 @@ def obter_pasta_por_nome(self, pasta_raiz: Folder, nome):
279
324
def obter_arquivo_por_nome (self , pasta : Folder , nome ):
280
325
arquivos = list (self .listar_arquivos (pasta ))
281
326
arquivo_encontrado = next ((arquivo for arquivo in arquivos if nome in arquivo .name ), None )
282
- return arquivo_encontrado
327
+ return arquivo_encontrado
0 commit comments