Fala pessoal!
Nesse post eu gostaria de compartilhar algumas soluções de como compactar e descompactar arquivos e diretórios pelo SQL Server. Isso é especialmente útil para criar rotinas de ETL onde você precisa utilizar esses recursos utilizando scripts T-SQL ou mesmo para compactar arquivos de backup gerados na versão Express (que não possui suporte a backups compactados).
Caso você tenha interesse em tratamento de arquivos pelo SQL Server, veja mais alguns posts sobre esse assunto:
– SQL Server – Operações com arquivos utilizando xp_cmdshell (Como listar, ler, escrever, copiar, excluir e mover arquivos)
– Como compactar diretórios em arquivos ZIP utilizando 7zip e CMD
– SQL Server – Como exportar dados do banco para arquivo texto (CLR, OLE, BCP)
– SQL Server – Como importar arquivos de texto para o banco (OLE Automation, CLR, BCP, BULK INSERT, OPENROWSET)
– SQL Server – Como listar, ler, escrever, copiar, excluir e mover arquivos com o CLR (C#)
– Operações com arquivos utilizando OLE Automation no SQL Server
– SQL Server – Como exportar e importar arquivos com dados tabulares (Ex: CSV) utilizando o CLR (C#)
– Importando arquivos CSV para o banco de dados SQL Server
– SQL Server – Como fazer uma integração com FTP e listar, enviar (upload) e baixar (download) arquivos utilizando o CLR (C#)
Como em algumas alternativas vou utilizar o 7-zip, vocês podem personalizar ainda mais os exemplos citados aqui consultando a documentação oficial do binário, bem completa e exemplificada.
Alternativa #1: Utilizando 7-zip e xp_cmdshell
Visualizar conteúdoPara ativar o xp_cmdshell, basta executar o comando abaixo:
sp_configure 'advanced options', 1
RECONFIGURE
GO
sp_configure 'xp_cmdshell', 1
RECONFIGURE
GO
Pré-requisito: 7-zip
Para que seja possível utilizar esse recurso, você precisará baixar os binários do 7-zip neste link. Você precisará baixar a versão “7-Zip Extra: standalone console version, 7z DLL, Plugin for Far Manager”, que vem no formato .7z.
Caso você não queira instalar o 7-zip no seu ambiente para poder abrir esse arquivo, vou disponibilizar os arquivos referentes ao standalone console version (versão 18.05) abaixo:
Versão x64 (recomendável) | Versão x86
Após baixar os arquivos, descompacte-os em algum diretório à sua escolha. Para os exemplos desse artigo, escolhi o diretório “C:\Binn\”.
Como compactar arquivos e diretórios
Para compactar arquivos e diretórios utilizando 7-zip e xp_cmdshell, você pode utilizar a Stored Procedure abaixo, que vai facilitar a sua utilização no dia a dia.
USE [dirceuresende]
GO
CREATE PROCEDURE dbo.stpCompacta_Arquivo (
@caminho VARCHAR(500),
@filtro VARCHAR(500),
@arquivoCompactado VARCHAR(500),
@nivelCompactacao INT = 5,
@recursivo BIT = 0,
@senha VARCHAR(100) = NULL
)
AS
BEGIN
DECLARE @caminhoBinario VARCHAR(255) = 'C:\Binn\7za.exe'
DECLARE @argumentos VARCHAR(MAX) = 'a -tzip -mx' + CAST(@nivelCompactacao AS VARCHAR(2)) + ' "' + @arquivoCompactado + '"' + (CASE WHEN @recursivo = 1 THEN ' -r' ELSE '' END) + (CASE WHEN NULLIF(LTRIM(RTRIM(@senha)), '') IS NOT NULL THEN ' -p' + @senha ELSE '' END) + ' "' + @caminho + '\' + @filtro + '" -mmt';
DECLARE @Comando VARCHAR(8000) = 'call "' + @caminhoBinario + '" ' + @argumentos
-- PRINT @Comando
EXEC xp_cmdshell @Comando
END
Exemplo de uso
Neste exemplo, vou demonstrar como compactar todos os arquivos e sub-diretórios do diretório “C:\Temporario\”, e salvando no arquivo “C:\Teste\Arquivo.zip”, com nível de compactação médio (5):
EXEC dbo.stpCompacta_Arquivo
@caminho = 'C:\Temporario\', -- varchar(500)
@filtro = '*', -- varchar(500)
@arquivoCompactado = 'C:\Teste\Arquivo.zip', -- varchar(500)
@nivelCompactacao = 5, -- int
@recursivo = 1 -- bit
Outros exemplos:
-- Modo básico
EXEC dbo.stpCompacta_Arquivo
@caminho = 'C:\Temporario', -- varchar(500)
@filtro = '*.txt', -- varchar(500)
@arquivoCompactado = 'C:\Teste\Arquivo.zip' -- varchar(500)
-- Compactando todos os arquivos que comecem com Teste%
EXEC dbo.stpCompacta_Arquivo
@caminho = 'C:\Temporario', -- varchar(500)
@filtro = 'Teste*', -- varchar(500)
@arquivoCompactado = 'C:\Teste\Arquivo.zip' -- varchar(500)
-- Compactando o arquivo "Teste.txt"
EXEC dbo.stpCompacta_Arquivo
@caminho = 'C:\Temporario', -- varchar(500)
@filtro = 'Teste.txt', -- varchar(500)
@arquivoCompactado = 'C:\Teste\Arquivo.zip' -- varchar(500)
/*
Compacta todos os arquivos com extensão .txt no diretório "C:\Temporario" (apenas na raiz, sem sub-diretórios),
usando compactação máxima (9) e protegendo o arquivo com a senha "dirceu"
*/
EXEC dbo.stpCompacta_Arquivo
@caminho = 'C:\Temporario', -- varchar(500)
@filtro = '*.txt', -- varchar(500)
@arquivoCompactado = 'C:\Teste\Arquivo.zip', -- varchar(500)
@nivelCompactacao = 9, -- int
@recursivo = 0, -- bit
@senha = 'dirceu' -- varchar(100)
Como descompactar arquivos e diretórios
Utilizando a Stored Procedure abaixo, podemos facilmente descompactar arquivos (com e sem senha) em algum diretório conforme a nossa necessidade. Vale ressaltar que, caso o diretório de destino não exista, ele será criado.
USE [dirceuresende]
GO
CREATE PROCEDURE dbo.stpDescompacta_Arquivo (
@arquivoCompactado VARCHAR(500),
@pastaDestino VARCHAR(500),
@filtro VARCHAR(500) = NULL,
@senha VARCHAR(100) = NULL
)
AS
BEGIN
DECLARE @caminhoBinario VARCHAR(255) = 'C:\Binn\7za.exe'
DECLARE @argumentos VARCHAR(MAX) = 'x "' + @arquivoCompactado + '" -aoa -o"' + @pastaDestino + '" ' + ISNULL(@filtro, '') + '' + (CASE WHEN NULLIF(LTRIM(RTRIM(@senha)), '') IS NOT NULL THEN ' -p' + @senha ELSE '' END) + ' -r -mmt';
DECLARE @Comando VARCHAR(8000) = 'call "' + @caminhoBinario + '" ' + @argumentos
PRINT @Comando
EXEC xp_cmdshell @Comando
END
Exemplos de uso:
-- Exemplo básico
EXEC dbo.stpDescompacta_Arquivo
@arquivoCompactado = 'C:\Teste\Arquivo.zip', -- varchar(500)
@pastaDestino = 'C:\Teste 2\'
-- Descompactando arquivos com senha
EXEC dbo.stpDescompacta_Arquivo
@arquivoCompactado = 'C:\Teste\Arquivo.zip', -- varchar(500)
@pastaDestino = 'C:\Teste 2\', -- varchar(100)
@senha = 'dirceu' -- varchar(100)
-- Descompactando apenas arquivos com extensão .txt
EXEC dbo.stpDescompacta_Arquivo
@arquivoCompactado = 'C:\Teste\Arquivo.zip', -- varchar(500)
@pastaDestino = 'C:\Teste 2\', -- varchar(100)
@filtro = '*.txt' -- varchar(100)
-- Descompactando apenas o arquivo "Teste.txt"
EXEC dbo.stpDescompacta_Arquivo
@arquivoCompactado = 'C:\Teste\Arquivo.zip', -- varchar(500)
@pastaDestino = 'C:\Teste 2\', -- varchar(100)
@filtro = 'Teste.txt' -- varchar(100)
Alternativa #2: Utilizando 7-zip e SQLCLR (C#)
Visualizar conteúdoCaso você não conheça ou não saiba o que é o SQLCLR, saiba mais acessando o post Introdução ao SQL CLR (Common Language Runtime) no SQL Server.
Pré-requisito: 7-zip
Para que seja possível utilizar esse recurso, você precisará baixar os binários do 7-zip neste link. Você precisará baixar a versão “7-Zip Extra: standalone console version, 7z DLL, Plugin for Far Manager”, que vem no formato .7z.
Caso você não queira instalar o 7-zip no seu ambiente para poder abrir esse arquivo, vou disponibilizar os arquivos referentes ao standalone console version (versão 18.05) abaixo:
Versão x64 (recomendável) | Versão x86
Após baixar os arquivos, descompacte-os em algum diretório à sua escolha. Para os exemplos desse artigo, escolhi o diretório “C:\Binn\”.
Código-fonte da solução
Abaixo, vou disponibilizar o código-fonte da solução de compactação utilizando 7-zip e SQLCLR.
Classe Retorno.cs (Exibir mensagens de alertas e erros)
using System;
using System.Data.SqlClient;
using Microsoft.SqlServer.Server;
namespace Bibliotecas.Model
{
public static class Retorno
{
public static void Erro(string erro)
{
Mensagem(erro);
throw new ApplicationException(erro);
}
public static void Mensagem(string mensagem)
{
using (var conexao = new SqlConnection("context connection=true"))
{
conexao.Open();
using (var comando = new SqlCommand("IF ( (512 & @@OPTIONS) = 512 ) select 1 else select 0", conexao))
{
if ((int)comando.ExecuteScalar() != 0) return;
}
var retorno = SqlContext.Pipe;
retorno?.Send(mensagem.Length > 4000 ? mensagem.Substring(0, 4000) : mensagem);
}
}
public static void RetornaReader(SqlDataReader dataReader)
{
var retorno = SqlContext.Pipe;
retorno?.Send(dataReader);
}
}
public class Ret : Exception
{
public Ret(string str) : base(str)
{
}
}
}
stpCompacta_Arquivo.cs
using System;
using System.Data.SqlTypes;
using System.IO;
using System.Text;
using System.Diagnostics;
using Bibliotecas.Model;
public partial class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void stpCompacta_Arquivo(SqlString caminho, SqlString filtro, SqlString arquivoCompactado, SqlInt32 nivelCompactacao, SqlString senha)
{
string[] arquivos;
#region tratamento de entradas
if (nivelCompactacao.Value < 0 || nivelCompactacao.Value > 9)
{
Retorno.Erro("Parametro inválido na variavel nivelCompactacao, use de 0 a 9 para compactar, sendo 9 o nivel mais alto (5 recomendado).");
return;
}
try
{
if (!Directory.Exists(caminho.Value))
{
Retorno.Erro($"O caminho especificado '{arquivoCompactado}' não existe ou está inacessivel.");
return;
}
}
catch
{
Retorno.Erro($"Erro ao converter caminho especificado ('{arquivoCompactado}').");
return;
}
try
{
arquivos = Directory.GetFiles(caminho.Value, filtro.Value);
}
catch
{
Retorno.Erro($"Erro ao listar arquivos no caminho especificado ({arquivoCompactado}).");
return;
}
var objetoArquivoCompactado = new FileInfo(arquivoCompactado.Value);
var diretorioArquivoCompactado = objetoArquivoCompactado.Directory?.ToString();
if (diretorioArquivoCompactado == null || !Directory.Exists(diretorioArquivoCompactado))
{
Retorno.Erro($"O caminho do arquivo compactado especificado ({diretorioArquivoCompactado}) não existe ou inacessível.");
return;
}
if (objetoArquivoCompactado.Extension.Trim() != "")
{
try
{
objetoArquivoCompactado.Delete();
}
catch
{
Retorno.Erro($"o arquivo compactado especificado ({arquivoCompactado.Value}) está sendo usado.");
return;
}
}
else
{
Retorno.Erro($"O arquivo compactado especificado não possui uma extensão válida ({objetoArquivoCompactado.Extension.Trim()}).");
return;
}
#endregion
try
{
var argumentos = $@" a -tzip -mx{nivelCompactacao.Value} ""{arquivoCompactado.Value}""" + (!senha.IsNull && !string.IsNullOrEmpty(senha.Value) ? $" -p{senha.Value} " : " ") + $@"""{caminho.Value}\{filtro.Value}"" -mmt";
using (var scriptProc = new Process { StartInfo = { FileName = @"C:\Binn\7za.exe", UseShellExecute = false, Arguments = argumentos, RedirectStandardOutput = true, RedirectStandardError = true, StandardOutputEncoding = Encoding.GetEncoding(850), StandardErrorEncoding = Encoding.GetEncoding(850), CreateNoWindow = true } })
{
scriptProc.Start();
var output = scriptProc.StandardOutput.ReadToEnd();
var erro = scriptProc.StandardError.ReadToEnd();
if (output.Length > 0)
{
//Retorno.Mensagem(output);
}
if (erro.Length > 0)
{
Retorno.Erro(erro);
}
}
var quantidadeArquivos = arquivos.Length;
Retorno.Mensagem("Total de: (" + quantidadeArquivos + ") arquivos foram compactados em: " + arquivoCompactado.Value);
}
catch (Exception e)
{
Retorno.Erro("Erro : " + e.Message);
}
}
};
Alternativa #3: Utilizando a SharpZipLib e SQLCLR (C#)
Visualizar conteúdoCaso você não conheça ou não saiba o que é o SQLCLR, saiba mais acessando o post Introdução ao SQL CLR (Common Language Runtime) no SQL Server.
Como a biblioteca SharpZipLib é bem grande, acaba ficando inviável disponibilizar todo o código fonte aqui no post, além também, da versão T-SQL. Por este motivo, vou disponibilizar links para fazer o download dos arquivos de código-fonte.
A solução completa do Visual Studio, onde você poderá editar o código livremente, está disponibilizada neste link.
Neste link aqui estou disponibilizando o código-fonte T-SQL, para permitir a criação dos objetos sem precisar instalar e nem abrir o Visual Studio.
Para entender melhor o parâmetro @filtro dessa solução, uma vez que ele é diferente das alternativas anteriores (que utilizam o 7-zip), recomendo a leitura da documentação oficial da biblioteca.
Como compactar arquivos e diretórios
-- Exemplo básico
EXEC dbo.stpCompacta_Arquivo
@caminho = 'C:\Temporario\',
@filtro = '*',
@arquivoCompactado = 'C:\Teste\Arquivo.zip',
@nivelCompactacao = 5,
@senha = ''
-- Compactando arquivos com extensão .txt e utilizando compactação máxima (9)
EXEC dbo.stpCompacta_Arquivo
@caminho = 'C:\Temporario\',
@filtro = '*',
@arquivoCompactado = 'C:\Teste\Arquivo.zip',
@nivelCompactacao = 9,
@senha = ''
-- Compactando arquivos e protegendo-os com senha
EXEC dbo.stpCompacta_Arquivo
@caminho = 'C:\Temporario\',
@filtro = '*',
@arquivoCompactado = 'C:\Teste\Arquivo.zip',
@nivelCompactacao = 5,
@senha = 'dirceu'
-- Compactando apenas o arquivo "Teste 1.txt"
EXEC dbo.stpCompacta_Arquivo
@caminho = 'C:\Temporario\',
@filtro = 'Teste 1.txt',
@arquivoCompactado = 'C:\Teste\Arquivo.zip',
@nivelCompactacao = 5,
@senha = ''
Como descompactar arquivos e diretórios
-- Exemplo básico
EXEC dbo.stpDescompacta_Arquivo
@arquivoCompactado = N'C:\Teste\Arquivo.zip', -- nvarchar(max)
@pastaDestino = N'C:\Teste\', -- nvarchar(max)
@filtro = N'', -- nvarchar(max)
@senha = N'' -- nvarchar(max)
-- Descompactando arquivos com senha
EXEC dbo.stpDescompacta_Arquivo
@arquivoCompactado = N'C:\Teste\Arquivo.zip', -- nvarchar(max)
@pastaDestino = N'C:\Teste\', -- nvarchar(max)
@filtro = N'', -- nvarchar(max)
@senha = N'dirceu' -- nvarchar(max)
-- Descompactando apenas arquivos com extensão .txt
EXEC dbo.stpDescompacta_Arquivo
@arquivoCompactado = N'C:\Teste\Arquivo.zip', -- nvarchar(max)
@pastaDestino = N'C:\Teste\', -- nvarchar(max)
@filtro = N'.txt', -- nvarchar(max)
@senha = N'' -- nvarchar(max)
-- Descompactando arquivos que começam com "Teste%"
EXEC dbo.stpDescompacta_Arquivo
@arquivoCompactado = N'C:\Teste\Arquivo.zip', -- nvarchar(max)
@pastaDestino = N'C:\Teste\', -- nvarchar(max)
@filtro = N'Teste*', -- nvarchar(max)
@senha = N'' -- nvarchar(max)
É isso aí, pessoal!
Espero que tenham gostado desse post, um abraço e até a próxima!
Dirceu Resende
Arquiteto de Banco de Dados e BI · Microsoft MVP · MCSE, MCSA, MCT, MTA, MCP.
Posts relacionados
Carregando…


Comentários (0)
Carregando comentários…