Por Que Minhas Imagens Estão Saindo Corrompidas?

Se você é um desenvolvedor Java que utiliza servlets e uploads de arquivos, pode ter encontrado um problema frustrante: imagens carregadas que aparecem corrompidas ao serem abertas. Isso pode ser perplexo, especialmente se arquivos de texto são enviados sem problemas. Neste post de blog, vamos explorar as razões pelas quais isso acontece e fornecer soluções claras para resolver o problema.

Entendendo o Problema

Ao trabalhar com uploads de arquivos, particularmente arquivos de imagem, é essencial lidar corretamente com dados binários. A saída corrompida geralmente indica que o fluxo binário não está sendo lido corretamente ou não está sendo gravado no arquivo de maneira correta. O segmento de código abaixo mostra um método típico de upload de arquivos usando Apache Commons FileUpload:

protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    ...
    BufferedInputStream stream = new BufferedInputStream(item.openStream());
    ...
}

Neste método, imagens e outros arquivos binários são processados, mas a forma como os dados são lidos pode levar a problemas que corrompem os arquivos de imagem.

Analisando o Código

Uma parte chave do código que contribui para o problema é encontrada dentro do método para ler bytes do fluxo de entrada. Aqui está o trecho de código relevante:

public static byte[] getBytes(InputStream src, int buffsize) throws IOException {
    ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
    byte[] buff = new byte[buffsize];

    while (true) {
        int nBytesRead = src.read(buff);
        if (nBytesRead < 0) {
            break;
        }
        byteStream.write(buff);
    }
    ...
}

Identificando o Problema

  • Gravação do Buffer Inteiro: A linha byteStream.write(buff); grava o buffer inteiro independentemente de quantos bytes foram realmente lidos. Isso é problemático porque, em muitos casos, nBytesRead será menor que o tamanho do buffer, o que significa que bytes restantes de leituras anteriores podem ser gravados na saída, resultando em corrupção.

Solução Sugerida

Para corrigir esse problema, precisamos ajustar como os bytes são gravados no ByteArrayOutputStream. O código revisado deve ter a seguinte aparência:

public static byte[] getBytes(InputStream src, int buffsize) throws IOException {
    ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
    byte[] buff = new byte[buffsize];

    while (true) {
        int nBytesRead = src.read(buff);
        if (nBytesRead < 0) {
            break;
        } else {
            byteStream.write(buff, 0, nBytesRead); // Grava apenas os bytes lidos
        }
    }
    ...
}

Mudanças Principais

  1. Gravação Condicional: A cláusula else garante que só gravemos os bytes que foram realmente lidos.
  2. Comprimento Especificado: Ao gravar, agora especificamos o número de bytes a serem gravados, usando byteStream.write(buff, 0, nBytesRead);.

Essas mudanças evitam que dados antigos e desnecessários sejam gravados e garantem que os arquivos de imagem sejam preservados sem corrupção.

Conclusão

Se você está enfrentando problemas com uploads de imagem em sua aplicação Java, o culpado muitas vezes reside na forma como você está manipulando o fluxo de entrada. Refinando sua lógica de leitura e gravação de byte-stream, você pode eliminar problemas que levam a imagens corrompidas.


Seguindo as diretrizes acima e corrigindo como você lê e escreve streams de bytes, você pode prevenir dores de cabeça futuras com uploads de arquivos em suas aplicações Java. Boa codificação!