2010-01-30 34 views
30

Tengo un gran CLOB (más de 32kB) que quiero leer en una cadena, usando StringBuilder. ¿Cómo hago esto de la manera más eficiente? No puedo usar el constructor "int length" para StringBuilder ya que la duración de mi CLOB es más larga que "int" y necesita un valor "largo".¿La solución más eficiente para leer CLOB en String, y String to CLOB en Java?

No soy tan cómodo con las clases de E/S Java y me gustaría obtener orientación.

Editar- he tratado con este código para 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(); 
} 
+0

¿Qué es exactamente lo que quiere hacer una vez que lea el CLOB en una cadena? –

+0

¿Quiere decir CLOB en el sentido de la base de datos, o simplemente "cadena grande"? – skaffman

+0

Sí, es un CLOB de una base de datos DB2. – Jonas

Respuesta

13

no puedo usar el constructor "int length" para StringBuilder ya que la longitud de mi CLOB es más largo que un int y necesita un valor long.

Si la longitud de CLOB es mayor que la que cabe en un int, los datos de CLOB tampoco caben en una cadena. Tendrá que usar un enfoque de transmisión para tratar con esta cantidad de datos XML.

Si la longitud real de la CLOB es menor que Integer.MAX_VALUE, simplemente forzar la long a int poniendo (int) en frente de ella.

+5

De hecho, si el tamaño del CLOB es más grande que 2^32 bytes, tienes grandes problemas – skaffman

+0

Sugeriría escribirlo en un archivo, si necesita todo el CLOB para procesar –

34

autorización I supondrá un uso general, primero hay que descargar apache commons, allí encontrará una clase de utilidad llamado IOUtils que tiene un método llamado copy();

Ahora la solución es: obtenga el flujo de entrada de su objeto CLOB usando getAsciiStream() y páselo al método copy().

InputStream in = clobObject.getAsciiStream(); 
StringWriter w = new StringWriter(); 
IOUtils.copy(in, w); 
String clobAsString = w.toString(); 
+0

Gracias, eso se ve bien. Pero levanto la pregunta un poco más, porque preferiría una solución que solo utiliza la biblioteca estándar. – Jonas

+0

Ya tengo la biblioteca de Apache Commons cargada, así que esta es la solución perfecta. ¡Gracias! –

+6

getAsciiStream le dará dolores de cabeza si usa Unicode. (o cualquier carácter que caiga fuera de ascii) –

2

Si realmente debe usar solo bibliotecas estándar, solo tiene que ampliar un poco la solución de Omar. (IOUtils de Apache es básicamente un conjunto de métodos de conveniencia lo que ahorra una gran cantidad de codificación)

Ya son capaces de obtener el flujo de entrada a través clobObject.getAsciiStream()

Sólo hay que "transferir manualmente" los caracteres a la 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(); 

tener en cuenta que

  1. Si su CLOB contiene más carácter que se ajuste a una cadena, esto no va a funcionar.
  2. Ajuste el InputStreamReader y StringWriter con BufferedReader y BufferedWriter respectivamente para un mejor rendimiento.
+0

Eso se parece al código que proporcioné en mi pregunta, ¿hay alguna diferencia clave entre ellos que yo no veo? En el ejemplo en un punto de vista del rendimiento? – Jonas

+0

Vaya, ¡me perdí el fragmento de código! Es algo similar, pero tenga en cuenta que con sólo tomar el BufferedReader.readLine(), se perderá los saltos de línea. –

+1

Corrección pequeña La línea 2 debe leer Reader = new InputStreamReader (in); – Vivek

13

Mi respuesta es simplemente un sabor de lo mismo. Pero lo probé con la serialización de un contenido comprimido y funcionó. Así que puedo confiar en esta solución a diferencia de la que se ofrece primero (que usa readLine) porque ignorará los saltos de línea y dañará la entrada.

/********************************************************************************************* 
* 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(); 
} 
10

¿Qué pasa con:

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

?

Por ejemplo Oracle oracle.sql.CLOB hacen getSubString() de char[] interna, que se define en oracle.jdbc.driver.T4CConnection y justo al lado System.arraycopy() y envoltura de String ... Nunca se consigue una lectura más rápida y luego System.arraycopy().

ACTUALIZACIÓN Obtener controlador ojdbc6.jar, y descompilar CLOB aplicación, y estudiar cuyo caso sería más rápido basado en el conocimiento internos.

+0

Deja una gran cantidad de caracteres de líneas nuevas en la cadena. – Gervase

+0

@Gervase Las líneas nuevas pueden ser significativas en XML. De todos modos, debes recortar espacios inútiles y líneas nuevas antes de almacenarlo en la base de datos. –

+0

Algunos puntos para aclarar: ¿Qué sucede si clob.length() es mayor que Integer.MAX_VALUE? ¿Qué es jar contiene oracle.sql.CLOB? – Stephan

0
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(); 
} 

El enfoque anterior también es muy eficiente.

1
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

CLOB son como archivos, se puede leer partes de ella fácilmente como esto

// read the first 1024 characters 
String str = myClob.getSubString(0, 1024); 

y se puede sobrescribir a ella como esto

// overwrite first 1024 chars with first 1024 chars in str 
myClob.setString(0, str,0,1024); 

No sugiero el uso de StringBuilder y llénelo hasta que obtenga una excepción, casi como agregar números ciegamente hasta que obtenga un desbordamiento. CLOB es como un archivo de texto y la mejor manera de leer que utiliza una memoria intermedia, en caso de tener que procesar, de lo contrario se puede transmitir en un archivo local como esto

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(); 
1

Si se utiliza la mula, a continuación se los pasos.

Siga los pasos a continuación.

habilitar la transmisión en el conector es decir progressiveStreaming = 2

Typecast DB2 ha devuelto a CLOB java.sql.Clob (IBM compatible con este tipo fundido)

Convierte eso a flujo de caracteres (ASCII corriente a veces puede no soportar algunos personajes especiales). Entonces puede usar getCharacterStream()

Eso devolverá un objeto "lector" que se puede convertir a "Cadena" utilizando common-io (IOUtils).

Así que, en resumen, utilice el componente groovy y añada el código siguiente.

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

Nota: Aquí estoy asumiendo "payload.field1" es la celebración de datos CLOB.

Eso es todo!

Saludos Naveen

0
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(); 
} 
+0

Por lo general, es mejor explicar una solución en lugar de simplemente publicar algunas filas de código anónimo. Puede leer [Cómo escribo una buena respuesta] (https://stackoverflow.com/help/how-to-answer), y también [Explicar respuestas totalmente basadas en código] (https://meta.stackexchange.com/questions/114762/explaining-entirely-% E2% 80% 8C% E2% 80% 8B-based-answers-answers) –