ResultSet e InputStream

8 respostas
ze_kiefa

Tenho um bean no qual eu recupero a sua foto de um banco de dados:

public class Pessoa{
  private int id;
  private String nome;
  private InputStream foto;
  
  // getters e setters omitidos
}
public class PessoaDAO{
 // outros métodos omitidos
 private void populaBean( ResultSet rs, Pessoa bean ) throws SQLException{
		bean.setId( rs.getInt("id") );
                bean.setNome( rs.getString("nome") );
                bean.setFoto( rs.getBinaryStream( "foto" ) );
 }
}

Quando eu tento exibir essa foto (em um Servlet, por exemplo) o JDBC lança uma exceção que o objeto já foi fechado (o ResultSet).

PessoaDAO dao = new PessoaDAO();
                int idPessoa = 99;
		Pessoa bean = dao.obter( idPessoa );
		InputStream entrada = bean.getFoto();
				
		try
		{
			// carrega o arquivo na Servlet
			response.setContentType("application/octet-stream");
			
			byte[] buffer = new byte[1024];
			int bytesLidos = -1;
			while ( (bytesLidos = entrada.read( buffer, 0, 1024 )) > 0 ) // a execção é lançada aqui
			{
				response.getOutputStream().write(buffer, 0, bytesLidos);
			}
			
			response.getOutputStream().flush(); 
			response.getOutputStream().close();
			entrada.close();
			
		}
		catch( IOException ioE )
		{
			ioE.printStackTrace(); 
		}

Exceção: [Microsoft][SQLServer 2000 Driver for JDBC]Object has been closed.

Dúvida: Há alguma maneira de desvincular o InputStream originado do ResultSet passado ao InputStream do bean (Pessoa.foto)?

8 Respostas

Leandro_Carvalho

Isso:
bean.setFoto( rs.getBinaryStream( “foto” ) );

Faz o seu InputStream “foto” apontar para o mesmo endereço de memória que o BinaryStream do ResultSet, quando aqui:

while ( (bytesLidos = entrada.read( buffer, 0, 1024 )) > 0 )

Você tenta acessar este endereço, o ResultSet já está fechado.

O que você precisa é que o InputStream “foto” tenha uma “cópia” deste InputStream e não seja o mesmo.

Espero que seja isso… :roll:

ze_kiefa

Esse é o objetivo: como fazer?

Leandro_Carvalho

Continuo achando que seu problema é conceitual… heheheh
Você precisa transportar o “byte[] buffer = new byte[1024];” e não o “InputStream”… :wink:

O InputStream só indica um lugar da memória onde começa os dados, assim que você fechar o ResultSet, eles não estarão mais lá, não adianta o que você faça, então você precisa pegar estes dados, guardá-los num array (como você faria depois, de qualquer jeito), fechar o ResultSet e então transportar o array… :slight_smile:

ze_kiefa

Ou seja, fazer a leitura em bytes diretamente no DAO e guardá-lo no bean, tornando-o independente do ResultSet?

L

Eu sugiro você alterar seu método setFoto() para ler do InputStream do banco de dados e armazená-lo no seu bean. Pode ser até em bytes como o Leandro disse ali, ou se quiser manter o mesmo InputStream, aí é com você.

ze_kiefa
public class PessoaDAO{
 // outros métodos omitidos
 private void populaBean( ResultSet rs, Pessoa bean ) throws SQLException
 {
	bean.setId( rs.getInt("id") );
        bean.setNome( rs.getString("nome") );
                
        byte[] buffer = new byte[1024];
	int bytesLidos = -1;
	while ( (bytesLidos = rs.getBinaryStream("foto").read( buffer, 0, 1024 )) > 0 )
	{
	  bean.setFoto( new ByteArrayInputStream( buffer ) );
	}
  }
}

Sugestão acatada (ainda tenho que testar, mas é só para dar um retorno!).
Se eu garantir que a foto tenha menos de 1 Mb (1024 bytes), eu posso trocar o while por if?

ze_kiefa

Uma pequena correção.

public class PessoaDAO{
 // outros métodos omitidos
 private void populaBean( ResultSet rs, Pessoa bean ) throws SQLException
 {
	bean.setId( rs.getInt("id") );
        bean.setNome( rs.getString("nome") );
        InputStream entrada = rs.getBinaryStream("foto");
        
        byte[] buffer = new byte[1024];
	int bytesLidos = -1;
	while ( (bytesLidos = entrada.read( buffer, 0, 1024 )) > 0 )
	{
	  bean.setFoto( new ByteArrayInputStream( buffer ) );
	}
  }
}

Mas uma dúvida ainda remanescente: como eu guardo um array de bytes[] no InputStream (Pessoa.foto), pois da forma como está implementado acima, a minha foto sairá incompleta?

ze_kiefa

Versão final funcionando.

public class PessoaDAO{
 // outros métodos omitidos
 private void populaBean( ResultSet rs, Pessoa bean ) throws SQLException
 {
	bean.setId( rs.getInt("id") );
        bean.setNome( rs.getString("nome") );
        
        InputStream entrada = rs.getBinaryStream("foto");
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
	int bytesLidos = -1;
	
        while ( (bytesLidos = entrada.read( buffer, 0, 1024 )) > 0 )
	{
	  bout.write( buffer );
	}
        
        bean.setFoto( new ByteArrayInputStream( bout.toByteArray() ) );    
  }
}


Obrigado Leandro e Lao!
Criado 18 de setembro de 2007
Ultima resposta 18 de set. de 2007
Respostas 8
Participantes 3