La solution la plus efficace pour lire CLOB à String, et String à CLOB en Java?
j'ai un gros sabot (plus de 32kB) que je veux lire à une chaîne, en utilisant StringBuilder. Comment puis-je le faire de la manière la plus efficace? Je ne peux pas utiliser le constructeur "int length" pour StringBuilder car la longueur de mon CLOB est plus longue qu'un "int" et nécessite une valeur "long".
Je ne suis pas très à l'aise avec les cours D'E/S en Java, et je voudrais obtenir quelques conseils.
Modifier -j'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();
}
11 réponses
Je ne peux pas utiliser le constructeur "int length" pour
StringBuilder
puisque la longueur de mon sabot est plus longue qu'unint
et unlong
valeur.
si la longueur du sabot est plus grande que celle d'un int, les données du sabot ne s'adapteront pas non plus à une chaîne de caractères. Vous devrez utiliser une approche de diffusion en continu pour traiter cette quantité de données XML.
si la longueur réelle du sabot est inférieure à Integer.MAX_VALUE
, juste de la force de l' long
int
en mettant (int)
en face de il.
Ok je suppose une utilisation générale, d'abord vous devez télécharger apache commons, vous y trouverez une classe utilitaire 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 en utilisant getAsciiStream() et passez-le à la méthode copy ().
InputStream in = clobObject.getAsciiStream();
StringWriter w = new StringWriter();
IOUtils.copy(in, w);
String clobAsString = w.toString();
ma réponse est juste une saveur de la même. Mais je l'ai testé en sérialisant un contenu zippé et ça a marché. Donc je peux faire confiance à cette solution contrairement à celle qui est offerte en premier (qui utilise readLine) parce qu'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();
}
What is wrong with:
clob.getSubString(1, (int) clob.length());
?
par exemple Oracle oracle.sql.CLOB
getSubString()
interne char[]
qui est défini dans oracle.jdbc.driver.T4CConnection
et System.arraycopy()
et la prochaine pellicule String
... Vous ne pouvez jamais lire plus vite alors System.arraycopy()
.
UPDATE Obtenir du pilote ojdbc6.jar, et décompiler CLOB
mise en oeuvre, et étudier quel cas serait plus rapide basée sur les connaissances internes.
si vous devez vraiment utiliser seulement les bibliothèques standard, alors vous avez juste à développer un peu la solution D'Omar. (Les outils d'Apache sont essentiellement un ensemble de méthodes pratiques qui économise beaucoup de codage)
vous pouvez déjà obtenir le flux d'entrée par clobObject.getAsciiStream()
vous avez juste à "transférer manuellement" les caractères au rédacteur de chaîne:
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
- si votre sabot contient plus de caractère que pourrait convenir à une chaîne, cela ne fonctionne pas.
- envelopper le InputStreamReader et le StringWriter avec BufferedReader et BufferedWriter respectivement pour une meilleure performance.
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;
}
si vous utilisez Mule, voici les étapes.
Suivez les étapes ci-dessous.
activer le streaming dans le connecteur i.e. progressiveStreaming=2
Typecast DB2 renvoie CLOB à java.SQL.Clob (IBM supporte ce type de distribution)
Convertissez cela en flux de caractères (le flux ASCII peut parfois ne pas supporter certains caractères spéciaux). Vous pouvez donc utiliser getCharacterStream ()
qui renvoie un objet "reader" qui peut être converti en "String"" utilisation de common-io (IOUtils).
bref, utilisez groovy component 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: ici je suppose " charge utile.field1 " détient des données clob.
C'est ça!
Salutations Naveen
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.
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();
}
une méthode d'aide conviviale utilisant apache commons.io
Reader reader = clob.getCharacterStream();
StringWriter writer = new StringWriter();
IOUtils.copy(reader, writer);
String clobContent = writer.toString();
CLOB sont comme des Fichiers, vous pouvez lire des pièces de facilement comme ceci
// read the first 1024 characters
String str = myClob.getSubString(0, 1024);
et vous pouvez écraser comme cela
// overwrite first 1024 chars with first 1024 chars in str
myClob.setString(0, str,0,1024);
Je ne suggère pas D'utiliser StringBuilder et de le remplir jusqu'à ce que vous obteniez une Exception, presque comme ajouter des nombres à l'aveugle jusqu'à ce que vous obteniez un débordement. Clob est comme un fichier texte et la meilleure façon de le lire est d'utiliser un tampon, au cas où vous auriez besoin de le traiter, sinon vous pouvez le streamer dans un fichier local comme celui-ci
int s = 0;
File f = new File("out.txt");
FileWriter fw new FileWriter(f);
while (s < myClob.length())
{
fw.write(myClob.getSubString(0, 1024));
s += 1024;
}
fw.flush();
fw.close();