web-dev-qa-db-fra.com

La solution la plus efficace pour lire CLOB to String et String to CLOB en Java?

J'ai un gros CLOB (plus de 32 Ko) que je veux lire dans une chaîne, en utilisant StringBuilder. Comment est-ce que je fais ceci de la manière la plus efficace? Je ne peux pas utiliser le constructeur "int length" pour StringBuilder car la longueur de mon objet CLOB est plus longue qu'un "int" et nécessite une valeur "long".

Je ne suis pas à l'aise avec les classes d'E/S Java et je souhaiterais obtenir des conseils.

ModifierJ'ai essayé avec ce code pour clobToString ():

private String clobToString(Clob data) {
    StringBuilder sb = new StringBuilder();
    try {
        Reader reader = data.getCharacterStream();
        BufferedReader br = new BufferedReader(reader);

        String line;
        while(null != (line = br.readLine())) {
            sb.append(line);
        }
        br.close();
    } catch (SQLException e) {
        // handle this exception
    } catch (IOException e) {
        // handle this exception
    }
    return sb.toString();
}
37
Jonas

Je ne peux pas utiliser le constructeur "int length" pour StringBuilder car la longueur de mon objet CLOB est plus longue que celle d'un int et nécessite une valeur long.

Si la longueur de CLOB est supérieure à ce qui convient à un int, les données CLOB ne tiendront pas non plus dans une chaîne. Vous devrez utiliser une approche de diffusion en continu pour traiter autant de données XML.

Si la longueur réelle de l'objet CLOB est inférieure à Integer.MAX_VALUE, forcez simplement la variable long à int en mettant (int) devant celle-ci.

17
Barend

Ok, je suppose un usage général. Vous devez d’abord télécharger Apache commons , vous y trouverez une classe d’utilitaires nommée IOUtils qui a une méthode nommée copy (); 

Maintenant, la solution est: récupérez le flux d'entrée de votre objet CLOB à l'aide de getAsciiStream () et transmettez-le à la méthode copy ().

InputStream in = clobObject.getAsciiStream();
StringWriter w = new StringWriter();
IOUtils.copy(in, w);
String clobAsString = w.toString();
41
Omar Al Kababji

Ma réponse est juste un avant-goût de la même chose. Mais je l'ai testé avec la sérialisation d'un contenu compressé et cela a fonctionné. Je peux donc faire confiance à cette solution contrairement à celle proposée en premier (qui utilise readLine) car elle ignorera les sauts de ligne et corrompra l'entrée.

/*********************************************************************************************
 * From CLOB to String
 * @return string representation of clob
 *********************************************************************************************/
private String clobToString(Java.sql.Clob data)
{
    final StringBuilder sb = new StringBuilder();

    try
    {
        final Reader         reader = data.getCharacterStream();
        final BufferedReader br     = new BufferedReader(reader);

        int b;
        while(-1 != (b = br.read()))
        {
            sb.append((char)b);
        }

        br.close();
    }
    catch (SQLException e)
    {
        log.error("SQL. Could not convert CLOB to string",e);
        return e.toString();
    }
    catch (IOException e)
    {
        log.error("IO. Could not convert CLOB to string",e);
        return e.toString();
    }

    return sb.toString();
}
18
Stan Sokolov

Quel est le problème avec:

clob.getSubString(1, (int) clob.length());

?

Par exemple, Oracle Oracle.sql.CLOB exécute getSubString() sur le char[] interne défini dans Oracle.jdbc.driver.T4CConnection et uniquement System.arraycopy() et le bouclage suivant à String... Vous ne lirez jamais plus vite que System.arraycopy().

UPDATE Obtenez le pilote ojdbc6.jar , décompilez la version CLOB et étudiez le cas le plus rapide en fonction des connaissances internes.

15
gavenkoa

Si vous ne devez utiliser que des bibliothèques standard, il vous suffit de développer un peu la solution de Omar. (Apache's IOUtils est fondamentalement juste un ensemble de méthodes pratiques qui permet d’économiser beaucoup de code)

Vous êtes déjà capable d’obtenir le flux d’entrée via clobObject.getAsciiStream()

Il vous suffit de "transférer manuellement" les caractères sur le StringWriter:

InputStream in = clobObject.getAsciiStream();
Reader read = new InputStreamReader(in);
StringWriter write = new StringWriter();

int c = -1;
while ((c = read.read()) != -1)
{
    write.write(c);
}
write.flush();
String s = write.toString();

Gardez à l'esprit que 

  1. Si votre clob contient plus de caractères qu’une chaîne, cela ne fonctionnera pas.
  2. Enveloppez InputStreamReader et StringWriter avec BufferedReader et BufferedWriter, respectivement, pour améliorer les performances.
4
Edwin Lee

Si vous utilisez Mule, voici les étapes.

Suivez les étapes ci-dessous.

Activer la diffusion en continu dans le connecteur, c'est-à-dire progressiveStreaming = 2

Typecast DB2 a renvoyé CLOB à Java.sql.Clob (IBM prend en charge cette conversion de type)

Convertissez cela en flux de caractères (les flux ASCII peuvent parfois ne pas prendre en charge certains caractères spéciaux). Donc, vous pouvez utiliser getCharacterStream ()

Cela retournera un objet "reader" qui peut être converti en "String" en utilisant common-io (IOUtils).

En bref, utilisez un composant groovy et ajoutez le code ci-dessous. 

clobTest = (Java.sql.Clob)payload.field1 
bodyText = clobTest.getCharacterStream() 
targetString = org.Apache.commons.io.IOUtils.toString(bodyText)
payload.PAYLOADHEADERS=targetString return payload

Remarque: Je suppose ici que "payload.field1" contient des données de type clob.

C'est tout!

Cordialement Naveen

3
Naveen K Reddy
private String convertToString(Java.sql.Clob data)
{
    final StringBuilder builder= new StringBuilder();

    try
    {
        final Reader         reader = data.getCharacterStream();
        final BufferedReader br     = new BufferedReader(reader);

        int b;
        while(-1 != (b = br.read()))
        {
            builder.append((char)b);
        }

        br.close();
    }
    catch (SQLException e)
    {
        log.error("Within SQLException, Could not convert CLOB to string",e);
        return e.toString();
    }
    catch (IOException e)
    {
        log.error("Within IOException, Could not convert CLOB to string",e);
        return e.toString();
    }
    //enter code here
    return builder.toString();
}
1
Hemant Tripathi
public static final String tryClob2String(final Object value)
{
    final Clob clobValue = (Clob) value;
    String result = null;

    try
    {
        final long clobLength = clobValue.length();

        if (clobLength < Integer.MIN_VALUE || clobLength > Integer.MAX_VALUE)
        {
            log.debug("CLOB size too big for String!");
        }
        else
        {
            result = clobValue.getSubString(1, (int) clobValue.length());
        }
    }
    catch (SQLException e)
    {
        log.error("tryClob2String ERROR: {}", e);
    }
    finally
    {
        if (clobValue != null)
        {
            try
            {
                clobValue.free();
            }
            catch (SQLException e)
            {
                log.error("CLOB FREE ERROR: {}", e);
            }
        }
    }

    return result;
}
1
kayz1
public static String readClob(Clob clob) throws SQLException, IOException {
    StringBuilder sb = new StringBuilder((int) clob.length());
    Reader r = clob.getCharacterStream();
    char[] cbuf = new char[2048];
    int n;
    while ((n = r.read(cbuf, 0, cbuf.length)) != -1) {
        sb.append(cbuf, 0, n);
    }
    return sb.toString();
}

L'approche ci-dessus est également très efficace.

0
Rohit

Une méthode d'assistance amicale utilisant Apache commons.io

Reader reader = clob.getCharacterStream();
StringWriter writer = new StringWriter();
IOUtils.copy(reader, writer);
String clobContent = writer.toString();
0
fl0w