es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Descargas incompletas de TIdHTTP FileStream

Estoy utilizando TIdHTTP.Get() para recuperar archivos (potencialmente grandes) en un TFileStream, básicamente;

filestream := TFileStream.Create(destination, fmCreate);
http.HandleRedirects := True;
try
  http.Get(url, filestream);
except
  on E: Exception do Memo.Lines.Add(E.Message);
end;
filestream.Free;

Mi problema es cuando el usuario cierra o finaliza el programa mientras se está realizando la descarga. En lugar de mostrar el tamaño del archivo más pequeño de lo que debería ser, el archivo tiene el tamaño de la descarga completada. ¿Por qué ocurre esto?

Utilizo el tamaño del archivo como una comprobación rápida para ver si la descarga fue exitosa, por lo que tener el tamaño correcto pero contenidos incorrectos genera otros errores. No quiero tener que realizar una comprobación de hash para cada archivo, ya que hay muchos, y la comprobación de MD5 lleva mucho tiempo en archivos de varios GB de tamaño.

¿Hay alguna manera de hacer que el tamaño del archivo de destino sea más pequeño si la descarga se interrumpe por cualquier motivo? ¿Alguna forma de no expandir el flujo al tamaño completo a menos que se haya completado toda la descarga correctamente?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    La razón por la cual el archivo tiene el tamaño de la descarga completada, incluso si la descarga se interrumpe, es porque el objeto TFileStream se crea con la bandera fmCreate. Esta bandera crea un nuevo archivo y trunca cualquier archivo existente a longitud cero si existe. Por lo tanto, aunque la descarga se interrumpa, el tamaño del archivo será el mismo que si la descarga se completara correctamente porque el archivo ya ha sido creado y truncado.

    Para mitigar este problema, puedes crear el objeto TFileStream utilizando la bandera fmOpenWrite en lugar de fmCreate. Esta bandera abre el archivo para escribir, pero preserva los datos existentes en el archivo. Luego, antes de descargar el archivo, puedes usar la propiedad TFileStream.Size para obtener el tamaño actual del archivo. Después de que la descarga esté completa, puedes comparar el tamaño actual del archivo con el tamaño esperado y eliminar el archivo si no coinciden.

    Aquí tienes un ejemplo de implementación:

    filestream := TFileStream.Create(destino, fmOpenWrite or fmShareDenyWrite);
    http.HandleRedirects := True;
    try
      // Obtener el tamaño esperado del archivo antes de la descarga
      tamañoEsperado := http.Head(url).ContentLength;
      http.Get(url, filestream);
      // Comprobar si el tamaño del archivo coincide con el tamaño esperado
      if filestream.Size <> tamañoEsperado then begin
        // Eliminar el archivo si los tamaños no coinciden
        filestream.Free;
        DeleteFile(destino);
      end;
    except
      on E: Exception do Memo.Lines.Add(E.Message);
    end;
    filestream.Free;
    

    Esta implementación utiliza el método TIdHTTP.Head() para obtener el tamaño esperado del archivo antes de la descarga. La propiedad ContentLength del objeto TIdHTTPResponse devuelto por Head() contiene el tamaño esperado del archivo, si está disponible.

    Si el tamaño del archivo no coincide con el tamaño esperado después de la descarga, el archivo se elimina utilizando la función DeleteFile(). Esto asegura que el archivo no quede en un estado incompleto o corrupto.

    Utilizando este enfoque, puedes evitar tener que verificar la integridad de cada archivo mediante el cálculo del hash, al tiempo que te aseguras de que el archivo descargado esté completo y sea correcto.

Comments are closed.