Executando verificação de segurança...
2

[C# .Net] Como compactar vários arquivos em um .zip e forçar o download

Para o dia a dia da empresa que trabalho (na qual também sou fundador), usamos um sistema simples de ticket system, feito em asp.net webforms, com layout baseado em bootstrap.

Esse sistema foi desenvolvido por nós mesmo da empresa, simplesmente pra ser o mais simples possível, o mais adaptado para as nossas realidades (os nossos sistemas) possível.

Também serviu durante muito tempo pra introduzir pessoas da nossa empresa, no básico de desenvolvimento que usamos, algo como um treinamento básico de asp.net webforms com C# e banco de dados em SQL Server.

Contudo, esses dias eu tinha que atender um ticket que tinha 10 arquivos anexos na mensagem de abertura e eu percebi que não existia um botão "baixar todos os anexos".

Resolvi implementar.

O código inicial, que existe até hoje para baixar apenas um anexo por vez é o seguinte:

// recupera o nome do arquivo que é um 'argument' de um repeater
string nomeArquivo = e.CommandArgument.ToString();

// monta o caminho completo do arquivo no servidor, concatenando a pasta com o nome do arquivo
string caminhoCompletoArquivo = Server.MapPath("~/TicketAnexo/") + nomeArquivo;

string pattern = string.Format("[{0}]", Regex.Escape(new string(Path.GetInvalidFileNameChars())));

// remove caracteres invalidos para nome de arquivos
string novoNomeArquivo = Regex.Replace(nomeArquivo, pattern, "");
string novoCaminhoCompletoArquivo = Path.Combine(Path.GetDirectoryName(caminhoCompletoArquivo), novoNomeArquivo);

FileInfo arquivo = new FileInfo(novoCaminhoCompletoArquivo);

// força o download
Response.Clear();
Response.AddHeader("Content-Disposition", "attachment; filename=" + arquivo.Name);
Response.AddHeader("Content-Length", arquivo.Length.ToString());
Response.ContentType = "application/octet-stream";
Response.WriteFile(arquivo.FullName);

Response.End();

Coloquei alguns comentários dentro do código, mas a ideia é basicamente encontrar o caminho físico do arquivo no servidor, iniciar uma classe 'FileInfo' e "Escrever" o arquivo no response utilizando 'Response.WriteFile(arquivo.FullName);'

Para a minha ideia de "baixar todos os anexos", eu não queria salvar os arquivos .zip depois de cria-lo. Por esse motivo o final, a parte de "escrever" o arquivo no response, ficou um pouco diferente.

O trecho de código que cria o arquivo .zip e faz um loop incluindo cada um dos arquivos que estão no ticket é o seguinte

byte[] compressedBytes;
string numeroTicket = string.Empty;

using (var outStream = new MemoryStream())
{
    //cria um arquivo .zip em memória
    using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
    {
        //loop na lista de caminhos dos arquivos anexos.
        foreach (var a in anexos)
        {
            numeroTicket = a.TicketComentario.Ticket.NumeroTicket;
            string nomeArquivo = a.Arquivo;
            string caminhoCompletoArquivo = Server.MapPath("~/TicketAnexo/") + nomeArquivo;
            
            //lê o arquivo como um array de bytes
            byte[] fileBytes = File.ReadAllBytes(caminhoCompletoArquivo);

            //inclui o arquivo no .zip
            var fileInArchive = archive.CreateEntry(nomeArquivo, CompressionLevel.Optimal);
            using (var entryStream = fileInArchive.Open())
            using (var fileToCompressStream = new MemoryStream(fileBytes))
            {
                fileToCompressStream.CopyTo(entryStream);
            }
        }
    }

    // cria um array de bytes para o arquivo .zip
    compressedBytes = outStream.ToArray();
}

Response.Clear();
Response.AddHeader("Content-Disposition", "attachment; filename=ticket_" + numeroTicket + "_anexos.zip");

Response.AddHeader("Content-Length", compressedBytes.Length.ToString());
Response.ContentType = "application/octet-stream";

// escreve um array de bytes no response
Response.BinaryWrite(compressedBytes);

Response.End();

Espero que esse código possa ajudar alguém.
Desejo que esse relato inspire pessoas também.
Nunca é tarde para melhorar o seu trabalho, suas ferramentas, o seu dia a dia.

Carregando publicação patrocinada...