Como receber um arquivo via rest no Server-side?

Bom dia, boa tarde ou boa noite… :grin:

Pessoal estou com uma certa dificuldade em ler um arquivo vindo via rest para o lado servidor, para ser mais específico, estou recebendo, por meio de JSON, um arquivo .zip, então, gostaria de saber como faço para ler esse arquivo em tempo de execução, descompactá-lo em memória (não quero gravar em disco), para então poder processá-lo.

Algumas das pesquisas que fiz (inclusive aqui no GUJ) não me ajudaram.

OBS: O arquivo .zip nada mais é que um arquivo .txt compactado, que devo descompactar do lado do servidor para obter um texto claro (text/plain) para ler e processar.

Está mandando arquivo dentro de um json, tem realmente essa necessidade ou seria por moda de usar json pra tudo? É mais fácil e apropriado receber diretamente o binário em uma requisiçao sem overhead do formato json para este caso. Tendo os bytes diretamente você usa alguma lib pra dezipar em memoria. Ai fica fácil encontrar solução pesquisando por exemplo: zip unzip bytes memory java.

application/octet-stream + custom headers são bem mais eficientes pra isso…

Pode não ser aquela delícia pra montar objetos, mas é bem mais gerenciável e elegante ( existe uma pseudo garantia nisso também )… Fora que Binário dentro de JSON dá uma treta gostosa com encode e é um saco de resolver.

Pode parecer lindo em teoria, tentei usar algo parecido uma vez, por experiencia própria foge Bino que é cilada! Se for continuar, boa sorte!

1 curtida

O mais comum para upload de arquivos eh uso multipart. Quanto a não fazer a descompactação do arquivo acho que não deveria ser um problema se vc fizer na pasta temporária do sistema operacional.

Galera, após muitas pesquisas na web, consegui resolver a treta, e deixar-vos-ei a resposta.
Estávamos tento uma grande dificuldade enviar o arquivo aberto em texto pleno, pois o tamanho do txt estava dando memory heap no front-end, então decidimos zipá-lo e depois codificá-lo em Base64, obtendo uma string pequena e enviando via requisição rest para o back-end.
No back-end, fizemos o seguinte:

/**
 * Realiza a decodificação do texto em Base64 para array de bytes.
 *
 * @param textoBase64 Texto em Base64.
 * @return Array de bytes do texto passado como parâmetro.
 */
private byte[] decodeBase64ToByteArray(String textoBase64) {
    return Base64.getDecoder().decode(textoBase64);
}

/**
 * Retorna o arquivo ZIP de um array de bytes.
 *
 * @param arquivoZip Array de bytes contendo as informações do arquivo ZIP.
 * @return Arquivo zip <tt>ZipInputStream</tt>.
 * @see ZipInputStream
 */
private ZipInputStream getZipFile(byte[] arquivoZip) {
    return new ZipInputStream(new ByteArrayInputStream(arquivoZip));
}

/**
 * Descompacta o arquivo ZIP e retorna em texto aberto.
 *
 * @param zipInput Objeto <tt>ZipInputStream</tt> contendo o arquivo zipado.
 * @return Texto aberto com o conteúdo do arquivo ZIP.
 * @see ZipInputStream
 */
private String unzipFile(ZipInputStream zipInput) throws Exception {
    byte[] buffer = new byte[209715200];
    ZipEntry ze;
    ByteArrayOutputStream baos;
    String conteudo = null;
    try {
        while ((ze = zipInput.getNextEntry()) != null) {
            int read = 0;
            baos = new ByteArrayOutputStream();
            while ((read = zipInput.read(buffer, 0, buffer.length)) != -1) {
                baos.write(buffer, 0, read);
            }
            baos.flush();
            conteudo = baos.toString("UTF-8");
            baos.close();
        }
    } catch (IOException e) {
        throw new IOException(e);
    } finally {
        ze = null;
        baos = null;
        System.gc();
    }
    return conteudo;
}

/**
 * Realiza a importação da Fita Espelho SIAPE.<br/>
 * <p>
 * O arquivo SIAPE deverá estar compactado no formato .ZIP e codificado em
 * Base64.<br/>
 * Este método decodificará o arquivo e realizará a descompactação dos dados
 * para realização da importação e processamento das informações, além das
 * validações iniciais necessárias para o
 * </p>
 *
 * @param textoBase64 Texto contento o conteúdo da Fita Espelho zipado e
 * codificado em Base64.
 */
public void importar(String textoBase64) {
    System.gc();

    byte[] arquivoZip;
    ZipInputStream zis;
    String conteudo = "";

    try {
        // Decodificando e convertendo o texto de Base64 para array de bytes.
        System.out.println("Decodificando e convertendo o texto de Base64 para array de bytes.");

        arquivoZip = this.decodeBase64ToByteArray(textoBase64);
        System.out.println("Concluído!");
        // Obtendo o arquivo ZIP.
        System.out.println("Obtendo e descompactando o arquivo ZIP.");
        zis = this.getZipFile(arquivoZip);
        // Unzipping
        conteudo = this.unzipFile(zis);
        zis.close();
        System.out.println("Concluído!");
        // Obtem o array de registros do arquivo SIAPE.
        System.out.println("Carregando os dados do arquivo SIAPE...");
        String[] arrayConteudo = conteudo.split("\n");
        // Obtem o header do arquivo.
        this.header = arrayConteudo[0].trim();

        // Restante do código ...

        System.out.println("Importação finalizada com sucesso!");

    } catch (IllegalArgumentException e) {
        Logger.getLogger(FitaEspelhoService.class.getName()).log(Level.SEVERE, e.getMessage(), e);
        EmsValidationException erro = new EmsValidationException();
        erro.addError("O arquivo informado não está codificado em Base64!\nPor favor, envie um arquivo compactado em formato ZIP e codificado em Base64.");
    } catch (EmsValidationException e) {
        throw new EmsValidationException(e.getErrors());
    } catch (Exception e) {
        Logger.getLogger(FitaEspelhoService.class.getName()).log(Level.SEVERE, e.getMessage(), e);
        EmsValidationException erro = new EmsValidationException();
        erro.addError(e.getLocalizedMessage());
        throw erro;
    } finally {
        zis = null;
        arquivoZip = null;
        conteudo = null;
    }

    System.gc();

}

Dessa forma conseguimos receber o arquivo e descompactá-lo em memória, tratando e trabalhando as informações existentes de acordo com as regras de negócio estabelecidas.

O tempo total gasto entre o envio do arquivo, a leitura e a persistência (sem aplicar as regras de negócio) foi cerca de 5 minutos (acredito que possa ser melhorado) para aproximadamente 160 mil registros.

Agradeço a ajuda de todos.