Compactar arquivo na memória

Amigos,
Java possui uma ou mais classes para compactar arquivos.

É possível compactar um arquivo apenas em memória do computador, sem gravá-lo no disco?

A intenção é compactar um arquivo texto selecionado pelo usuário, mantendo o arquivo compactado na memória do PC, transmitir esse arquivo compactado utilizando socket e depois descartá-lo da memória, sem ter que criar provavelmente uma pasta e um arquivo físico na máquina do usuário.

Opa, você sempre pode armazenar o conteúdo do arquivo (compactado ou não) como um array de bytes.
Dado que as classes de compactação usam InputStream e OutputStream, talvez você possa usar as implementações ByteArrayInputStream e ByteArrayOutputStream pra quebrar este galho pra você em memória.

[quote=kicolobo]Opa, você sempre pode armazenar o conteúdo do arquivo (compactado ou não) como um array de bytes.
Dado que as classes de compactação usam InputStream e OutputStream, talvez você possa usar as implementações ByteArrayInputStream e ByteArrayOutputStream pra quebrar este galho pra você em memória.[/quote]

Valeu pela dica!

Você consegue dar uma pequena demonstração via código?

package guj;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;

public class ExemploCompressaoArquivos {

    public void comprimirParaArquivo(String arqEntrada, String arqSaida) throws IOException {
        GZIPOutputStream gzos = null;
        BufferedInputStream bis = null;
        byte[] buffer = new byte[8 * 1024];
        try {
            int nBytes;
            bis = new BufferedInputStream(new FileInputStream(arqEntrada));
            gzos = new GZIPOutputStream(new BufferedOutputStream(new FileOutputStream(arqSaida)));
            while ((nBytes = bis.read(buffer)) > 0)
                gzos.write(buffer, 0, nBytes);
        } finally {
            gzos.close();
            bis.close();
        }
    }

    public byte[] comprimirParaMemoria(String arqEntrada) throws IOException {
        GZIPOutputStream gzos = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BufferedInputStream bis = null;
        byte[] buffer = new byte[8 * 1024];
        try {
            int nBytes;
            bis = new BufferedInputStream(new FileInputStream(arqEntrada));
            gzos = new GZIPOutputStream(baos);
            while ((nBytes = bis.read(buffer)) > 0)
                gzos.write(buffer, 0, nBytes);
        } finally {
            gzos.close();
            bis.close();
        }
        return baos.toByteArray();
    }

    /**
     * @param args
     */
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        ExemploCompressaoArquivos eca = new ExemploCompressaoArquivos();
        eca.comprimirParaArquivo(args[0], args[1]);
        byte[] bytes = eca.comprimirParaMemoria(args[0]);
        System.out.println(bytes.length); // confronte com o arquivo de saída para ver se ficou do mesmo tamanho
    }

}

Use gzip -d para descompactar o arquivo gerado e ver se ele bate com o original.

[quote=bezier curve][code]
package guj;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;

public class ExemploCompressaoArquivos {

public void comprimirParaArquivo(String arqEntrada, String arqSaida) throws IOException {
    GZIPOutputStream gzos = null;
    BufferedInputStream bis = null;
    byte[] buffer = new byte[8 * 1024];
    try {
        int nBytes;
        bis = new BufferedInputStream(new FileInputStream(arqEntrada));
        gzos = new GZIPOutputStream(new BufferedOutputStream(new FileOutputStream(arqSaida)));
        while ((nBytes = bis.read(buffer)) > 0)
            gzos.write(buffer, 0, nBytes);
    } finally {
        gzos.close();
        bis.close();
    }
}

public byte[] comprimirParaMemoria(String arqEntrada) throws IOException {
    GZIPOutputStream gzos = null;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    BufferedInputStream bis = null;
    byte[] buffer = new byte[8 * 1024];
    try {
        int nBytes;
        bis = new BufferedInputStream(new FileInputStream(arqEntrada));
        gzos = new GZIPOutputStream(baos);
        while ((nBytes = bis.read(buffer)) > 0)
            gzos.write(buffer, 0, nBytes);
    } finally {
        gzos.close();
        bis.close();
    }
    return baos.toByteArray();
}

/**
 * @param args
 */
public static void main(String[] args) throws IOException {
    // TODO Auto-generated method stub
    ExemploCompressaoArquivos eca = new ExemploCompressaoArquivos();
    eca.comprimirParaArquivo(args[0], args[1]);
    byte[] bytes = eca.comprimirParaMemoria(args[0]);
    System.out.println(bytes.length); // confronte com o arquivo de saída para ver se ficou do mesmo tamanho
}

}
[/code]

Use gzip -d para descompactar o arquivo gerado e ver se ele bate com o original. [/quote]

Obrigado pela ajuda.

Acabei utilizando o método abaixo que utiliza as classes Zip.

[code] // Compacta arquivo na memória
public byte[] compactarArquivo(String arqEntrada) throws IOException {
int cont;
byte[] dados = new byte[4096];

    BufferedInputStream origem;
    FileInputStream streamDeEntrada;
    ByteArrayOutputStream destino;
    ZipOutputStream saida;
    ZipEntry entry;

    try {
        destino = new ByteArrayOutputStream();
        saida = new ZipOutputStream(new BufferedOutputStream(destino));
        File f = new File(arqEntrada);
        streamDeEntrada = new FileInputStream(f);
        origem = new BufferedInputStream(streamDeEntrada, 4096);
        entry = new ZipEntry(f.getName());
        saida.putNextEntry(entry);

        while ((cont = origem.read(dados, 0, 4096)) != -1) {
            saida.write(dados, 0, cont);
            notificarObservadores(Util.PROCESSANDO);
        }
        origem.close();
        saida.close();
        return destino.toByteArray();
    } catch (IOException e) {
        throw new IOException(e.getMessage());
    }
}

[/code]

Isso é má prática. A mensagem de erro é uma das coisas menos informativas de uma exceção (esse tipo de coisa que você fez destrói o stack trace, por exemplo).
Em vez disso, simplesmente não ponha um try/catch (já que você disse que seu método “throws IOException”) ou então faça algo como:

    } catch (IOException e) {  
        // faça alguma coisa interessante, e então:
        throw e;
    }

[quote=entanglement][quote]

    } catch (IOException e) {  
        throw new IOException(e.getMessage());  
    }

[/quote]

Isso é má prática. A mensagem de erro é uma das coisas menos informativas de uma exceção (esse tipo de coisa que você fez destrói o stack trace, por exemplo).
Em vez disso, simplesmente não ponha um try/catch (já que você disse que seu método “throws IOException”) ou então faça algo como:

    } catch (IOException e) {  
        // faça alguma coisa interessante, e então:
        throw e;
    }

[/quote]

Valeu pela sugestão.

Eu copiei o código faz algum tempo da internet e fui alterando alguma coisa.

O que seria melhor? Manter ou tirar o try/catch?

Veja o código do Bezier Curve (ele usou um try/finally para forçar o fechamento dos arquivos. )
Não se esqueça: tudo que abriu, feche. Toalha molhada? Não é para largar em cima da cama e sim no cabide ou no varal.