Uma solução prática para otimizar o espaço ocupado é a compactação dos arquivos, principalmente se o objetivo é enviá-lo via E-Mail, contribuindo, desta forma, com a otimização da banda de comunicação e com o espaço utilizado para armazenamento nos servidores de E-Mail que vão, porventura, receber os arquivos, minimizando, desta forma, a possibilidade de erros no servidor de E-Mail destino devido ao recebimento de arquivos muito grandes.
Até a versão 9i do banco de dados, para implementar tal recurso de forma a funcionar embutido no sistema, era necessário ou criar um procedimento Java no banco de dados ou criar um Shell script que permitisse tal funcionalidade antes de enviar o arquivo.
A partir da versão 10g, a Oracle disponibilizou tal recurso diretamente no PL/SQL, o que simplifica tal processo e ainda pode ser utilizado para compactar qualquer tipo de arquivo, seja ele um arquivo texto ou binário que vai ser enviado por E-Mail ou vai ser carregado num campo LOB do banco de dados.
Esta demonstração tem por objetivo apresentar a uma opção de código que permita utilizar as funções de compactação do PL/SQL.
Taxas de Compactação
O parâmetro p_qualidade define o nível de compactação que será utilizado. Esse parâmetro pode variar de 1 a 9, sendo que 1 apresenta um menor nível de compactação, gerando um arquivo maior e 9 apresenta um maior nível de compactação, gerando um arquivo menor. Pode-se assumir por padrão a execução em nível 9 com objetivo de se obter um arquivo menor.
Código
O código abaixo pode ser executado a partir da versao 10g:
create or replace procedure compacta_arquivo (p_diretorio in varchar2 --> Diretorio do arquivo
,p_arq_origem in varchar2 --> Arquivo Origem
,p_arq_destino in varchar2 --> Arquivo destino
,p_qualidade in binary_integer --> Qualidade da compactação
,p_remove_org in varchar2 --> Remove Origem
,p_retorno out varchar2) IS --> Retorno de erro
BEGIN
--> Checando os parametros
IF p_diretorio is null THEN
p_retorno := 'Nome do diretorio deve ser informado';
ELSIF p_arq_origem is null THEN
p_retorno := 'Nome do arquivo de origem deve ser informado';
ELSIF p_arq_destino is null THEN
p_retorno := 'Nome do arquivo de destino deve ser informado';
ELSIF p_arq_origem = p_arq_destino THEN
p_retorno := 'Nome do arquivo de origem deve ser deferente do nome do arquivo de destino';
ELSIF UPPER(p_remove_org) not in ('S','N') THEN
p_retorno := 'Opção de Remoção do arquivo de origem deve ser S para sim e N para não';
ELSIF p_qualidade not in (1,2,3,4,5,6,7,8,9) THEN
p_retorno := 'Qualidade deve estar entre 1 (Menor compressao) e 9 (Maior compressao)';
ELSE
DECLARE
--> Variaveis Auxiliares
v_fp UTL_FILE.file_type;
v_bin_arq BFILE;
v_arq_compact BLOB;
v_buffer RAW(32767);
v_init_pos NUMBER := 1;
v_end_pos NUMBER;
v_tam_bloco BINARY_INTEGER := 32767;
BEGIN
--> Atribuindo o nome do arquivo que queremos compactar.
v_bin_arq := BFILENAME (p_diretorio, p_arq_origem);
--> Atribuindo o arquivo.
DBMS_LOB.fileopen (v_bin_arq);
--> Criando um BLOB que vai ser usado para armazenar o arquivo compactado
DBMS_LOB.createtemporary (v_arq_compact, TRUE, DBMS_LOB.session);
--> Compactando o arquivo em uma variavel BLOB
v_arq_compact := UTL_COMPRESS.lz_compress (v_bin_arq, p_qualidade);
--> Posição final do arquivo.
v_end_pos := DBMS_LOB.getlength (v_arq_compact);
v_fp := UTL_FILE.fopen (p_diretorio, p_arq_destino, 'wb',32767);
--> Gravando o arquivo compactado no arquivo de saída.
WHILE v_init_pos < v_end_pos LOOP
--> Lendo o arquivo
DBMS_LOB.read (v_arq_compact, v_tam_bloco, v_init_pos, v_buffer);
UTL_FILE.put_raw (v_fp, v_buffer);
v_init_pos := v_init_pos + v_tam_bloco;
v_buffer := NULL;
END LOOP;
--> Fechando os arquivos e liberando memória.
UTL_FILE.fclose (v_fp);
DBMS_LOB.filecloseall;
DBMS_LOB.freetemporary (v_arq_compact);
--> Removendo o arquivo
IF UPPER(p_remove_org) = 'S' THEN
UTL_FILE.fremove (p_diretorio,p_arq_origem);
END IF;
EXCEPTION
WHEN others THEN
p_retorno := sqlerrm;
END;
END IF;
END compacta_arquivo;



