A geração de arquivos texto em sistemas de banco de dados é muito comum é geralmente um dos responsáveis por uma parte significativa do volume de dados gerado pelo sistema.
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;