GARANTIR DESCONTO

Fórum Manipulando campos BLOB e CLOB com JDBC #567666

09/04/2009

0

[b][u]Manipulando campos BLOB e CLOB com JDBC[/u][/b] Por: Giovane Roslindo Kuhn Este tutorial apresenta de forma sucinta como manipular campos dos tipos BLOB e CLOB utilizando o driver Oracle JDBC (ojdbc14.jar). Em linhas gerais, a prova de conceito possui os seguintes passos: 1) ler um arquivo texto (grande) e um arquivo binário (imagem); 2) inserir o conteúdo destes arquivos em um registro no banco de dados utilizando JDBC; 3) selecionar o registro do banco e ler o conteúdo dos campos BLOB e CLOB utilizando JDBC; 4) gerar um arquivo binário com o conteúdo do campo BLOB e um arquivo texto com o conteúdo do campo CLOB; 5) certificar que o conteúdo dos arquivos gerados é idêntico ao conteúdo dos arquivos originais; Para o entendimento deste tutorial é necessário algum conhecimento em JDBC e SQL, para isto veja em: [url=http://www.javafree.org/javabb/viewtopic.jbb?t=1356]Acessando banco de dados em Java (PARTE 1)[/url] [url=http://www.javafree.org/javabb/viewtopic.jbb?t=1357]Acessando banco de dados em Java (PARTE 2)[/url] [url=http://www.javafree.org/javabb/viewtopic.jbb?t=1358]Acessando banco de dados em Java (PARTE 3)[/url] Let's play !!! [b][u]Preparando o ambiente[/u][/b] A preparação do ambiente para a prova de conceito tem os seguintes passos: 1) criação da tabela de testes com os campos BLOB e CLOB, segue definição:
create table teste (cadastro number(19), imagem blob, texto clob)
2) criação do arquivo binário (teste.jpg) 3) criação do arquivo texto (teste.txt) PS: Não é necessário preparar manualmente o ambiente, pois o programa de teste executa os passos descritos acima. [b][u]Inserindo registro[/u][/b] Para criar um registro, primeiramente deve ser inserido um registro com os campos CLOB e BLOB vazios:
Statement stmt = conn.createStatement();
stmt.execute("insert into teste (cadastro, imagem, texto) values (1, empty_blob(), empty_clob())");
Depois deve-se selecionar o registro e efetivamente inserir o conteúdo dos campos CLOB e BLOB, para isto o registro é bloqueado com a cláusula "for update":
ResultSet rs = stmt.executeQuery("select cadastro, imagem, texto from teste where cadastro = 1 for update");
rs.next();
Segue o código para atribuir o conteúdo do arquivo binário para o campo BLOB, nota-se que uma linha é específica para o driver Oracle, para outros drivers utilizar a linha comentada:
// copia arquivo para campo blob
Blob blob = rs.getBlob("imagem");
byte[] bbuf = new byte[1024];
InputStream bin = new FileInputStream(byteFile);
OutputStream bout = ((BLOB) blob).getBinaryOutputStream(); // específico driver oracle
// cout = clob.setCharacterStream(0);
int bytesRead = 0;
while ((bytesRead = bin.read(bbuf)) != -1) {
    bout.write(bbuf, 0, bytesRead);
}
bin.close();
bout.close();
Segue o código para atribuir o conteúdo do arquivo texto para o campo CLOB, nota-se que uma linha é específica para o driver Oracle, para outros drivers utilizar a linha comentada:
// copia arquivo para campo clob
Clob clob = rs.getClob("texto");
char[] cbuf = new char[1024];
Reader cin = new FileReader(file);
Writer cout = ((CLOB) clob).getCharacterOutputStream(); // específico driver oracle
// cout = clob.setCharacterStream(0);
int charsRead = 0;
while ((charsRead = cin.read(cbuf)) != -1) {
    cout.write(cbuf, 0, charsRead);
}
cin.close();
cout.close();
Basta comitar a transação e fechar o cursor:
// comita transação
conn.commit();
rs.close();
[b][u]Selecionando registro[/u][/b] O próximo objetivo da prova de conceito é selecionar o registro inserido e criar um novo arquivo binário com o campo BLOB e outro para o campo CLOB. Primeiro é selecionado o registro, um "select" normal:
rs = stmt.executeQuery("select cadastro, imagem, texto from teste where cadastro = 1");
rs.next();
Depois é criado um novo arquivo binário com o conteúdo do campo BLOB:
// cria novo arquivo binário com blob
blob = rs.getBlob("imagem");
bin = blob.getBinaryStream();
bout = new FileOutputStream(byteFileDb);
while ((bytesRead = bin.read(bbuf)) != -1) {
    bout.write(bbuf, 0, bytesRead);
}
bin.close();
bout.close();
Depois é criado um novo arquivo texto com o conteúdo do campo CLOB:
// cria novo arquivo texto com clob
clob = rs.getClob("texto");
cin = clob.getCharacterStream();
cout = new FileWriter(fileDb);
while ((charsRead = cin.read(cbuf)) != -1) {
    cout.write(cbuf, 0, charsRead);
}
cin.close();
cout.close();
Para finalizar é fechado o cursor:
// fecha cursor
rs.close();
[b][u]Validando arquivos[/u][/b] Para validar a prova de conceito é feito uma comparação entre os arquivos originais e os arquivos novos, segue código que verifica se o conteúdo de dois arquivos são iguais:
/**
 * Compara dois arquivos caracter a caracter
 * @param f1 Arquivo um
 * @param f2 Arquivo dois
 * @return <code>true</code> se forem iguais, <code>false</code> se não forem
 */
private static boolean equals(File f1, File f2) throws IOException {

    FileReader r1 = new FileReader(f1);
    FileReader r2 = new FileReader(f2);

    while (true) {
        int c1 = r1.read();
        int c2 = r2.read();
        if (c1 != c2) {
            return false;
        }
        if (c1 == -1 && c2 == -1) {
            break;
        }
    }
    return true;
}
Primeiro verifica os arquivos binários:
// arquivos binarios devem ser iguais
if (equals(byteFile, byteFileDb)) {
    System.out.println(byteFile.toString() + " == " + byteFileDb.toString());
} else {
    System.err.println(byteFile.toString() + " <> " + byteFileDb.toString());
}
E por fim, verifica os arquivos textos:
// arquivos texto devem ser iguais
if (equals(file, fileDb)) {
    System.out.println(file.toString() + " == " + fileDb.toString());
} else {
    System.out.println(file.toString() + " <> " + fileDb.toString());
}
Well, done !!! [url=mailto:brain@netuno.com.br][b]Giovane Roslindo Kuhn[/b][/url] é bacharel em Ciências da Computação pela [url=http://www.furb.br]Universidade Regional de Blumenau[/url]. Atuando profissionalmente no Projeto Jakare da empresa [url=http://www.senior.com.br]Senior Sistemas[/url], que consiste em um framework para desenvolvimento de aplicações J2EE e é reponsável pelos projetos [url=http://www.babaxp.org]Baba XP[/url], [url=http://snaildb.dev.java.net]SnailDB[/url] e [url=http://apollo.dev.java.net]Apollo[/url]. Incentivador do uso de metodologias ágeis de desenvolvimento, especialmente XP e desing patterns.
Giovane Kuhn

Giovane Kuhn

Responder

Posts

09/04/2009

Giovane Kuhn

Segue fonte completo:
Responder

Gostei + 0

09/04/2009

Vitor Pamplona

Agiliza um pouco ae :D
    private static boolean equals(File f1, File f2) throws IOException {

        if (f1.length() != f2.length()) return false;

        FileReader r1 = new FileReader(f1);
        FileReader r2 = new FileReader(f2);
        while (true) {
            int c1 = r1.read();
            int c2 = r2.read();
            if (c1 != c2) {
                return false;
            }
            if (c1 == -1 && c2 == -1) {
                break;
            }
        }
        return true;
    }
Responder

Gostei + 0

09/04/2009

Bruno Navarro

ei kuhn, esse tutorial q vc fez... me diz uma coisa... vc vai colocar isso no seu curriculum como 'artigos publicados' ???? pretende fazer mestrado ou algo do tipo? abracao
Responder

Gostei + 0

09/04/2009

Giovane Kuhn

[quote="bb"]ei kuhn, esse tutorial q vc fez... me diz uma coisa... vc vai colocar isso no seu curriculum como 'artigos publicados' ???? pretende fazer mestrado ou algo do tipo? abracao
Opa... na real estes tipos de artigos nem contam para a carreira acadêmica... escrevo estes tipos de artigos para auxiliar a comunidade Java e nada mais =DDD !!! Quanto ao mestrado, tem fortes pretensões !!!! Vamos ver se final do ano rola !!! Mas pq a curiosidade cara ??? []'s
Responder

Gostei + 0

09/04/2009

Bruno Navarro

eh pq meu chefe tah afim de fazer mestrado tb., e tah afim de fazer tipo umas pesquisas pra contar pontos saca., publicar artigos e etc... entao eu tava wondering se esse tutorial nao poderia ser na pratica um artigo publicado., soh isso :D
Responder

Gostei + 0

09/04/2009

Giovane Kuhn

Eh... acho difícil artigos deste gênero auxiliarem o seu chefe para ingressar num mestrado !!! Mas sem sobra de dúvida auxiliariam e muito a galera Java :o :o :o !!! Flow
Responder

Gostei + 0

09/04/2009

Achilles Bisneto

A pergunta vai parecer meio boba, mas tô me batento aqui. Se o campo CLOB não for um arquivo ou uma imagem, se for simplemente uma string gigantesca, um texto, eu até consigo pegar o campo clob e transformar de volta a string, mas quando servidor é linux essa string vem com caracteres estranhos no lugar da acentução ou cedilha, engraçado que o servidor no windows não acontece isso. Vocês podem me dar uma luz?
Responder

Gostei + 0

09/04/2009

Andre Valdestilhas

Tenho um campo Blob que gravo um objeto tipo HashMap, mas quando vou tentar recupera-lo da minha base de dados ele volta como um array de bytes, como faço pra converter devolta em um HashMap. Agradecido, André Valdestilhas
Responder

Gostei + 0

09/04/2009

Gustavo Gatto

Cara deixa eu explicar o que eu quero fazer: eu tenho um site onde tem notícias, como o corpo desta notícia tem o tamanho maior que 4.000 caracteres tive que optar pelo campo CLOB, porém tenho um número grande de jornalistas na qual podem inserir notícias ao mesmo tempo... Eu sou iniciante em java e to completamente perdido em relação a isto. Eu preciso que os dados do formulário, inclusive a notícia tamanho família, vá para o banco de dados... Eu consegui inserir dados neste campo, apenas utilizando um arquivo texto com o conteúdo, mas não posso depender de um arquivo, pois podem haver mais de um jornalista naquele mesmo instante cadastrando uma notícia... E estas não podem se conflitar e nem gerar sobrecarregamento de E/S... O que preciso não é nada de outro mundo, mas tô emperrado nisto e não consigo solucionar... please, help-me!
Responder

Gostei + 0

09/04/2009

Gustavo Gatto

Responder

Gostei + 0

09/04/2009

Giovane Kuhn

[quote="firmao"]Tenho um campo Blob que gravo um objeto tipo HashMap, mas quando vou tentar recupera-lo da minha base de dados ele volta como um array de bytes, como faço pra converter devolta em um HashMap. Agradecido, André Valdestilhas
André, recomendo você utilizar a serialização do Java para colocar o [i]HashMap[/i] no campo BLOB do banco, para isto utilize a classe [i]ObjectOutputStream[/i], por exemplo:
// hashmap a ser gravado no banco
HashMap map = new HashMap();
ObjectOutputStream oout = new ObjectOutputStream(((BLOB) blob).getBinaryOutputStream());
oout.writeObject(map);
oout.close();
Para ler utilize classe [i]ObjectInputStream[/i], por exemplo:
// le hashmap do banco
ObjectInputStream oin = new ObjectInputStream(blob.getBinaryStream());
HashMap map = (HashMap) oin.readObject();
oin.close();
Eu não testei estes dois códigos, mas qq coisa só berra novamente, flow !
Responder

Gostei + 0

09/04/2009

Giovane Kuhn

[quote="gustavogatto"]Cara deixa eu explicar o que eu quero fazer: eu tenho um site onde tem notícias, como o corpo desta notícia tem o tamanho maior que 4.000 caracteres tive que optar pelo campo CLOB, porém tenho um número grande de jornalistas na qual podem inserir notícias ao mesmo tempo... Eu sou iniciante em java e to completamente perdido em relação a isto. Eu preciso que os dados do formulário, inclusive a notícia tamanho família, vá para o banco de dados... Eu consegui inserir dados neste campo, apenas utilizando um arquivo texto com o conteúdo, mas não posso depender de um arquivo, pois podem haver mais de um jornalista naquele mesmo instante cadastrando uma notícia... E estas não podem se conflitar e nem gerar sobrecarregamento de E/S... O que preciso não é nada de outro mundo, mas tô emperrado nisto e não consigo solucionar... please, help-me!
Gustavo, Não precisas criar um arquivo e depois ler deste arquivo, podes trabalhar diretamente com [i]String[/i] que vem da sua tela de cadastro. Para inserir o valor no campo CLOB, no lugar da classe [i]FileReader[/i], utilize a classe [i]StringReader[/i]. Para ler o valor do campo CLOB para uma [i]String[/i], no lugar da classe [i]FileWriter[/i], utilize a classe [i]StringWriter[/i] e depois o método [i]getBuffer()[/i]. Qq coisa berra novamente, flow !!
Responder

Gostei + 0

09/04/2009

Giovane Kuhn

[quote="Achilles"]A pergunta vai parecer meio boba, mas tô me batento aqui. Se o campo CLOB não for um arquivo ou uma imagem, se for simplemente uma string gigantesca, um texto, eu até consigo pegar o campo clob e transformar de volta a string, mas quando servidor é linux essa string vem com caracteres estranhos no lugar da acentução ou cedilha, engraçado que o servidor no windows não acontece isso. Vocês podem me dar uma luz?
Achilles, Este problema normalmente ocorre devido problemas de configuração do "charset" do seu banco de dados. Leia a respeito de "charset" ou "character encoding". QQ novidade posta pra gente aí !!!
Responder

Gostei + 0

09/04/2009

Gustavo Gatto

[quote="brain"]Gustavo, Não precisas criar um arquivo e depois ler deste arquivo, podes trabalhar diretamente com [i]String[/i] que vem da sua tela de cadastro. Para inserir o valor no campo CLOB, no lugar da classe [i]FileReader[/i], utilize a classe [i]StringReader[/i]. Para ler o valor do campo CLOB para uma [i]String[/i], no lugar da classe [i]FileWriter[/i], utilize a classe [i]StringWriter[/i] e depois o método [i]getBuffer()[/i]. Qq coisa berra novamente, flow !!
Opa.. deu certo, mas estou com outro problema...
ERRO: java.lang.RuntimeException: java.io.IOException: Não serão lidos mais dados do soquete
Meu post segue no link: [url]http://www.javafree.org/javabb/viewtopic.jbb?t=851545[/url]
Responder

Gostei + 0

09/04/2009

Marcelo Luciano

Pessoal, consegui fazer o Upload gravar no campo Blob, mas to com 2 probleminhas: 1 - nao está fazendo upload de arquivos maiores que 4kb (mesmo eu tendo alterado no file.setSizeMax(50*1024*1024); caso o arquivo tenha 5kb por exemplo, já não faz upload informando a seguinte exceção "tamanho dos dados maior que o tamanho máximo para este tipo: "tamanho do arquivo""; 2 - como fazer a recuperação desse arquivo que foi gravado como array de bytes e mostralo no formao original??; Alguém tem alguma ideia de como fazer ele aceitar arquivos de qualquer tamanho e recuperar o arquivo no BD????? obs:já coloquei (-1) no lugar do 50*1024*1024 e continua a mesma coisa!! Valew)
Responder

Gostei + 0

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar