Download arquivos grandes em .NET

9 minuto(s) de leitura - April 02, 2022

01


Essa dica será muito importante quando você precisar fazer download de arquivos grandes e não possuir um migrador oficial para tal execução.

Introdução

Pois bem, sabemos que existem inúmeras formas de fazer download de arquivos na internet, mas .NET o HTTP Client é o mais utilizado sem sombra de dúvidas e atende muito bem muitos cenários.

O problema que enfrentamos basicamente é sobre muitas abordagens que vemos por aí, que funciona apenas para arquivos pequenos, que é por exemplo escrever os bytes usando o MemoryStream e depois escrever em um arquivo como demonstrado abaixo:
//...
const string url = "https://ralms.io/poeira_em_alto_mar.mp4";
using (var response = await client.GetAsync(url))
using (var streamContent = await response.Content.ReadAsStreamAsync())
{
    string tempFile = Path.GetTempFileName();
    using (var streamWrite = File.Open(tempFile, FileMode.Create))
    {
        await streamContent.CopyToAsync(streamWrite);
    } 
} 

Entendendo o problema

Com o código apresentado acima, temos 2 (dois) pequenos problemas... o primeiro é que ao fazer a solicitação do arquivo, você irá ter que aguardar que o servidor escreva todo binário para o solicitante, pra depois você receber um status de OK, se o arquivos for muito grande seu sistema poderá ficar muito ocioso, então você pode melhor um pouco essa requisição passando mais parâmetros para o GET (HttpCompletionOption.ResponseHeadersRead), falando que assim que os headers forem escritos já é o suficiente para ler StatusCode e a partir daí você tomar uma decisão de negócio, como por exemplo analisar o tamanho do arquivo que pode vir no header.
Vamos fazer essa pequena modificação:
//...
const string url = "https://ralms.io/poeira_em_alto_mar.mp4";
using (var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
using (var streamContent = await response.Content.ReadAsStreamAsync())
{
    string tempFile = Path.GetTempFileName();
    using (var streamWrite = File.Open(tempFile, FileMode.Create))
    {
        await streamContent.CopyToAsync(streamWrite);
    } 
} 

Resolvendo o problema

Ainda continuamos com um problema da leitura do content completamente, porque falo isso? Bom, o motivo é que se você tem pouca memória, você pode chegar ao ponto de exaurir seus recursos computacionais, então a dica é fragmentar a leitura do dado e escrever em pedaços menores em seu arquivo, isso se torna muito mais eficiente e você pode inclusive utilizar até paralelismo, veja como poderemos fazer de forma simples e resolver esse problema:

// ...
const string url = "https://ralms.io/poeira_em_alto_mar.mp4";
const int chunck = 1024 * 1024 * 5; //5Mb

using (var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
using (var streamContent = await response.Content.ReadAsStreamAsync())
{
    string tempFile = Path.GetTempFileName();
    using (var streamWrite = new FileStream(tempFile, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, chunck, FileOptions.SequentialScan))
    {
        await streamContent.CopyToAsync(streamWrite, chunck); //5Mb
    } 
} 

Observações

No exemplo acima fragmentamos em pedaços de 5Mb isso se torna mais eficiente e seguro, pricipalmente em ambientes que são containeralizados… é uma simples dica de trabalhar sobre o HTTP Client, mas que pode lhe ajudar em seu dia a dia!

Contatos

Fico por aqui, mas pode me contatar por meio de minhas redes sociais 😄
twitter: @ralmsdeveloper
linkedin: @ralmsdeveloper

Categorias: ,

Atualizado em:

Deixe um comentário