O uso de mecanismos para a compactação de arquivos é, sem sombra de dúvidas, um recurso bastante difundido no meio empresarial. Devido ao grande volume de informações processadas, diversas técnicas são empregadas com intuito de reduzir a quantidade de dados, tentando com isto maximizar o potencial de utilização dos meios de armazenamento e/ou transmissão.

Cópias de segurança (backups) são um exemplo notório de aplicação de meios para a compactação de informações. A realização de backups é um recurso vital em qualquer tipo de negócio, uma vez que possibilita a rápida recuperação de dados essenciais, viabilizando assim a retomada das operações rotineiras tão logo ocorram situações consideradas como desastrosas. A importância das cópias de segurança é atestada pelo enfoque dado a este tipo de questão por muitas auditorias corporativas, com uma série de procedimentos determinando que informações se prestam à realização de backups, além da periodicidade a ser levada em conta neste último caso.

Um dos formatos de compactação mais conhecidos é o ZIP. Este padrão aberto surgiu ainda em 1989, tendo passado por uma série de evoluções desde então. Sobre estruturas baseadas nesta especificação (extensão .zip), é comum que as mesmas possuam várias pastas e arquivos como parte de seus respectivos conteúdos, sendo possível inclusive configurar a taxa com a qual tais itens serão comprimidos (maior compactação significa, normalmente, um maior tempo em operações que envolvam a descompressão de arquivos).

O processo de descompactação de arquivos .zip também oferece uma flexibilidade considerável. Existe a alternativa de se descompactar um arquivo específico, sem que isto se traduza na necessidade de efetuar tal ação sobre todo o conteúdo que se está manipulando. A este comportamento que permite a execução de operações sobre um arquivo específico dá-se o nome de acesso randômico.

Todas essas características aqui mencionadas estão entre as razões que contribuíram para a popularização do padrão ZIP. Este formato é a base utilizada na geração de arquivos JAR (bibliotecas contendo classes e outros recursos Java compactados), no novo padrão para documentos, planilhas e apresentações do pacote Office (Open XML), além de ser suportado nativamente pelo próprio Windows (existem inclusive funcionalidades do sistema operacional que envolvem o uso de recursos de compactação).

A plataforma .NET conta desde a versão 2.0 com mecanismos que permitem a compactação de arquivos: trata-se da classe GZipStream (namespace System.IO.Compression). Contudo este tipo apresentava algumas limitações, como a impossibilidade de se comprimir vários arquivos numa mesma estrutura. Isso levou ao surgimento de alternativas que procuravam suprir esta demanda, sendo um bom exemplo disto a biblioteca SharpLibZip.

Já com o .NET Framework 3.5 seriam disponibilizadas as classes Package e PackagePart (namespace System.IO.Packaging). A partir de então, a plataforma .NET passou a contar com a capacidade de manipulação de arquivos compactados com uma estrutura mais complexa (considerando inclusive pastas com arquivos vinculados às mesmas).

Com o lançamento do .NET 4.5 outros melhoramentos foram introduzidos no que se refere ao suporte do formato ZIP. A finalidade deste artigo é descrever o funcionamento das classes ZipFile) e ZipArchive, as quais foram disponibilizadas neste nova versão do Framework. Para isto, serão apresentados a seguir alguns exemplos de trechos de código que utilizam esses tipos.

Utilizando as classes ZipFile e ZipArchive em aplicações .NET

Antes de iniciar a discussão sobre as características das classes ZipFile e ZipArchive, é necessário ressaltar que referências a duas bibliotecas precisarão ser adicionadas a projetos que venham a empregar esses tipos.

Este procedimento pode ser realizado, dentro do Solution Explorer do Visual Studio 2012, clicando com o botão direito sobre o item "References" de um projeto e selecionando na sequência a opção "Add Reference...".

Aparecerá então a janela “Reference Manager”. Em “Assemblies > Framework” localizar as bibliotecas “System.IO.Compression” e “System.IO.Compression.FileSystem”, selecionando as mesmas (Figura 1). Acionar finalmente o botão “OK”, de maneira que a referências seja incluídas no projeto que se estiver criando.

Adicionando referências à bibliotecas de compressão a um projeto

Figura 1: Adicionando referências à bibliotecas de compressão a um projeto

ZipFile será a primeira das classes abordada por este artigo. Trata-se de um tipo estático, o qual disponibiliza métodos que podem ser usados em operação de criação, extração ou leitura de arquivos gerado segundo o padrão ZIP.

Supondo que seja preciso compactar toda uma estrutura de diretórios e arquivos de um projeto ASP.NET, como aquela que consta na Figura 2.

Exemplo de estrutura de diretórios e arquivos a ser compactada

Figura 2: Exemplo de estrutura de diretórios e arquivos a ser compactada

A Listagem 1 apresenta um exemplo de como isto pode ser feito através da classe ZipFile. No caso, foi utilizado o método CreateFromDirectory, o qual cria um novo arquivo .zip a partir de um diretório específico; devem ser fornecidos como parâmetros a esta operação:

  • O caminho do diretório que estará sendo comprimido;
  • O nome do arquivo no formato .zip que será gerado como resultado do processamento;
  • O nível de compressão do arquivo a ser criado. Para este parâmetro é necessário utilizar um dos valores disponíveis para o enumeration CompressionLevel (namespace System.IO.Compression): Optimal (utiliza-se o maior grau de compactação possível, por mais que esta tarefa possa demandar um tempo maior), Fastest (prioriza-se a velocidade do processo de compactação, mesmo que com isto não se atinja o melhor índice possível), NoCompression (os diferentes itens adicionados a um arquivo .zip não estarão comprimidos);
  • Um valor booleano que, em caso afirmativo, indica que o nome do diretório-base será incluido na hierarquia de pastas a serem compactadas (neste exemplo específico, definiu-se o valor “false”, de forma que não exista dentro do arquivo .zip uma pasta de nome ArquivosACompactar como diretório inicial).

Listagem 1: Exemplo de utilização do método CreateFromDirectory da classe ZipFile


...

ZipFile.CreateFromDirectory(
    @"C:\Temp\TesteCompactacao\ArquivosACompactar\",
    @"C:\Temp\TesteCompactacao\Exemplo01.zip",
    CompressionLevel.Optimal,
    false);

...

Após a execução do trecho de código da Listagem 1, um arquivo de nome “Exemplo01.zip” terá sido criado conforme especificado na chamada ao método CreateFromDirectory (Figura 3).

Visualizando o conteúdo deste arquivo, será possível confirmar que o mesmo foi gerado seguindo a mesma estrutura de arquivos e pastas do diretório informado originalmente (Figura 4).

Arquivo .zip que foi gerado a partir do método CreateFromDirectory

Figura 3: Arquivo .zip que foi gerado a partir do método CreateFromDirectory

Visualizando o conteúdo do arquivo .zip gerado via método CreateFromDirectory

Figura 4: Visualizando o conteúdo do arquivo .zip gerado via método CreateFromDirectory

Já na Listagem 2 está um exemplo de uso da operação ExtractToDirectory. Esse método estático recebe como parâmetros o nome de um arquivo .zip, além do diretório de destino em que será descompactado o conteúdo deste último.

Listagem 2: Exemplo de utilização do método ExtractToDirectory da classe ZipFile


...

ZipFile.ExtractToDirectory(
    @"C:\Temp\TesteCompactacao\Exemplo01.zip",
    @"C:\Temp\TesteCompactacao\ArquivosDescompactados\");

...

O processamento da instrução que consta na Listagem 2 irá descompactar todo o conteúdo do arquivo “Exemplo01.zip” no diretório que foi definido como destino (Figura 5).

Conteúdo de arquivo .zip descompactado via método ExtractToDirectory

Figura 5: Conteúdo de arquivo .zip descompactado via método ExtractToDirectory

Além do tipo estático ZipFile, a classe ZipArchive também oferece uma série de funcionalidades que visam facilitar a implementação de funcionalidades baseadas na manipulação de arquivos compactados.

ZipArchive é um tipo que corresponde a uma representação de um arquivo .zip. Em termos práticos, isto significa que por meio dessa estrutura poderão ser executadas operações individuais sobre os itens de um arquivo .zip.

Cada elemento compactado dentro de um arquivo .zip equivale a uma instância do tipo ZipArchiveEntry (namespace System.IO.Compression), a qual pode ser obtida através de uma chamada ao método GetEntry com uma referência da classe ZipArchive. A identificação de um objeto ZipArchiveEntry corresponde ao caminho de um elemento dentro de um arquivo .zip (possíveis pastas + nome do arquivo que está compactado).

Dentre as ações possíveis empregando os tipos ZipArchive e ZipArchiveEntry estão: a inclusão de novos arquivos, atualizações no conteúdo de tais elementos, exclusões de itens ou ainda, a leitura individual destes.

O exemplo que consta na Listagem 3 faz uso das classes ZipFile, ZipArchive e ZipArchiveEntry simultaneamente, a fim de com isto extrair dois itens que constam no arquivo .zip criado anteriormente.

O método Open de ZipFile permite a abertura de um arquivo compactado, recebendo como parâmetros o caminho deste, além de que modo isto ocorrerá. Para este último parâmetro, deverá ser utilizado um dos valores do enumeration ZipArchiveMode (namespace System.IO.Compression):

  • Read: carregamento de um arquivo .zip para a realização somente de operações de leitura;
  • Create: permite apenas a inclusão de novos itens a um arquivo .zip;
  • Update: permite tanto a realização de operações de leitura, quanto escrita em um arquivo zipado.

No trecho de código apresentado na Listagem 3, definiu-se que o arquivo “Exemplo01.zip” será aberto para a leitura, para que se consiga com isso proceder com a extração de alguns dos elementos armazenados no mesmo (valor de enumeration ZipArchiveMode.Read). A partir de instâncias da classe ZipArchiveEntry é acionado o método ExtractToFile, de maneira que a descompactação de um item gere um novo arquivo (com base no caminho que foi passado como parâmetro).

A execução desse conjunto de instruções será responsável pela geração de dois arquivos em um diretório de testes, conforme indicado na Figura 6.

Listagem 3: Exemplo de utilização das classes ZipFile e ZipArchive


...

using (ZipArchive archive = ZipFile.Open(
    @"C:\Temp\TesteCompactacao\Exemplo01.zip",
    ZipArchiveMode.Read))
{
    string caminhoBaseExtracao = 
        @"C:\Temp\TesteCompactacao\ExtracaoZipArchive\";

    ZipArchiveEntry entry1 =
        archive.GetEntry(@"ProjetoExemplo.sln");
    entry1.ExtractToFile(
        caminhoBaseExtracao + "ProjetoExemplo.sln");

    ZipArchiveEntry entry2 =
        archive.GetEntry(@"ProjetoExemplo\Default.aspx");
    entry2.ExtractToFile(
        caminhoBaseExtracao + "Default.aspx");
} 

...
Arquivos descompactados por meio das classes ZipFile, ZipArchive e ZipArchiveEntry

Figura 6: Arquivos descompactados por meio das classes ZipFile, ZipArchive e ZipArchiveEntry

Por fim, a Listagem 4 apresenta um exemplo de criação de um arquivo .zip.

Neste último caso, está sendo invocado o método Open de ZipFile, informando-se ao mesmo o valor de enumeration ZipArchiveMode.Create. Esta ação resultará na criação de um novo arquivo .zip e, consequentemente, na geração de uma instância do tipo ZipArchive (já habilitada para a inclusão de itens que ficarão compactados).

Chamadas à operação CreateEntryFromFile são então efetuadas utilizando a referência da classe ZipArchive, de maneira a se incluírem itens ao arquivo .zip que se está manipulando. Este método recebe como parâmetros:

  • O caminho do elemento que será adicionado ao arquivo .zip;
  • O nome de tal elemento dentro do arquivo .zip considerado;
  • O grau de compactação do arquivo que se está comprimindo (a partir de um dos valores possíveis para o enumeration ZipArchiveMode).

Listagem 4: Criação de arquivo .zip com as classes ZipFile e ZipArchive


...

using (ZipArchive archive = ZipFile.Open(
    @"C:\Temp\TesteCompactacao\Exemplo02.zip",
    ZipArchiveMode.Create))
{
    string caminhoBaseOrigem =
        @"C:\Temp\TesteCompactacao\ArquivosACompactar\";

    archive.CreateEntryFromFile(
        caminhoBaseOrigem + "ProjetoExemplo.sln",
        "ProjetoExemplo.sln",
        CompressionLevel.Optimal);
    
    archive.CreateEntryFromFile(
        caminhoBaseOrigem + @"ProjetoExemplo\Default.aspx",
        @"ProjetoExemplo\Default.aspx",
        CompressionLevel.Optimal);
} 

...

A execução do código que está na Listagem 4 produzirá como resultado um arquivo com conteúdo similar àquele que consta na Figura 7.

Arquivos criado através das classes ZipFile e ZipArchive

Figura 7: Arquivos criado através das classes ZipFile e ZipArchive

Conclusão

Conforme detalhado no transcorrer deste artigo, as novas classes do .NET 4.5 para manipulação de arquivos .zip (ZipFile e ZipArchive) simplificam consideravelmente a implementação de funcionalidades que envolvam o uso de técnicas de compactação. Os diferentes recursos oferecidos por esses tipos permitem a realização de operações sofisticadas, sem que isso implique em grandes esforços de codificação.

Espero que o conteúdo aqui abordado possa lhe ser útil. Até uma próxima oportunidade!