2010-01-30 2 views
30

У меня есть большой CLOB (более 32 КБ), который я хочу прочитать в String, используя StringBuilder. Как мне сделать это наиболее эффективным способом? Я не могу использовать конструктор «длина строки» для StringBuilder, так как длина моего CLOB больше, чем «int», и ему требуется «длинное» значение.Наиболее эффективное решение для чтения CLOB в String и String для CLOB в Java?

Я не настолько удобен для классов Java I/O и хотел бы получить некоторые рекомендации.

Редактировать - Я попытался с этим кодом для 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

Что именно вы хотите сделать, как только вы читаете CLOB в строку? –

+0

Вы имеете в виду CLOB в базе данных, или просто «большая строка»? – skaffman

+0

Да, это CLOB из базы данных DB2. – Jonas

ответ

13

Я не могу использовать «длину ИНТ» конструктор для StringBuilder, так как длина моего CLOB больше, чем int и нуждается значение long.

Если длина CLOB больше, чем подходит для int, данные CLOB также не будут помещаться в строку. Вы должны будете использовать потоковый подход для обработки данных XML.

Если фактическая длина CLOB меньше Integer.MAX_VALUE, просто заставить long к int, поставив (int) перед ним.

+5

Действительно, если размер CLOB больше, чем 2^32 байта, у вас большие проблемы – skaffman

+0

Я бы предложил записать его в файл, если ему нужен весь CLOB для обработки –

34

Хорошо я полагаю, общее использование, сначала вы должны загрузить apache commons, там вы найдете утилиту класса с именем IOUtils, который имеет метод copy();

Теперь решение: получить входной поток объекта CLOB с помощью getAsciiStream() и передать его методу copy().

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

Спасибо, это выглядит красиво. Но я задаю вопрос немного больше, потому что я предпочел бы решение, которое использует только стандартную библиотеку. – Jonas

+0

У меня уже есть библиотека Apache Commons, поэтому это идеальное решение. Благодаря! –

+6

getAsciiStream даст вам головные боли, если вы используете unicode. (или любые символы, выпавшие за пределы ascii) –

2

Если вы действительно должны использовать только стандартные библиотеки, вам просто нужно немного расширить решение Omar. (IOUtils Apache является в основном просто набором удобных методов, которые экономят много кодирования)

Вы уже в состоянии получить входной поток через clobObject.getAsciiStream()

Вы просто должны «вручную переносить» символы к 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(); 

Имейте в виду, что

  1. Если CLOB содержит больше символов, чем будет соответствовать строка, это не будет работать.
  2. Оберните InputStreamReader и StringWriter с BufferedReader и BufferedWriter соответственно для лучшей производительности.
+0

. Это похоже на код, представленный в моем вопрос, есть ли какие-то ключевые различия между ними, которых я не вижу? В примере с точки зрения производительности? – Jonas

+0

К сожалению, я пропустил фрагмент кода! Это несколько похоже, но имейте в виду, что, просто захватив BufferedReader.readLine(), вы пропустите строки. –

+1

Строка малой коррекции 2 должна считываться считывателем = new InputStreamReader (in); – Vivek

13

Мой ответ - это просто аромат того же самого. Но я тестировал его с сериализацией сжатого содержимого, и он работал. Поэтому я могу доверять этому решению в отличие от предложенного в первую очередь (который использует readLine), потому что он будет игнорировать разрывы строк и испортить ввод.

/********************************************************************************************* 
* 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

Что случилось с:

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

?

Например Oracle oracle.sql.CLOB сделать getSubString() из внутренней char[], которые определены в oracle.jdbc.driver.T4CConnection и просто System.arraycopy() и рядом обертка для String ... Вы никогда не получите быстрее читать то System.arraycopy().

UPDATE Получить драйвер ojdbc6.jar и декомпилировать CLOB реализации, и изучение которых дело будет быстрее на основе внутренних органов знаний.

+0

Листья много строк символов в строке. – Gervase

+0

@ Gervase Newlines может быть значительным в XML. Во всяком случае, вы должны убрать бесполезные пространства и новые строки перед тем, как сохранить их в БД. –

+0

Некоторые моменты для очистки: что произойдет, если clob.length() больше Integer.MAX_VALUE? Что такое jar содержит 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(); 
} 

Вышеуказанный подход также очень эффективен.

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, как файлы, вы можете прочитать его части легко, как этот

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

и вы можете переписать на него, как этот

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

Я не предлагаю использовать StringBuilder и заполнить его до тех пор, пока вы не получите исключение, почти как добавление чисел вслепую, пока вы не получите переполнение. Clob, как текстовый файл, и лучший способ, чтобы читать ее с использованием буфера, в случае, если вам нужно обработать его, в противном случае вы можете передавать его в локальный файл, как этот

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

При использовании Mule, ниже шаги.

Следуйте инструкциям ниже.

Включить потоковый в разъеме т.е. progressiveStreaming = 2

DB2 вернулся напечатанный материал CLOB в java.sql.Clob (IBM поддерживает этот тип литой)

Преобразовать, что поток символов (ASCII поток иногда может не поддерживать некоторые специальные символы). Таким образом, вы можете использовать getCharacterStream()

Это вернет объект «читатель», который можно преобразовать в «String», используя common-io (IOUtils).

Короче говоря, используйте составной компонент и добавьте ниже код.

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

Примечание: Здесь я предполагаю, что "payload.field1" держит данные CLOB.

Вот и все!

Привет Навин

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

Обычно лучше объяснять решение, а не просто публиковать несколько строк анонимного кода. Вы можете прочитать [Как написать хороший ответ] (https://stackoverflow.com/help/how-to-answer), а также [Объяснение полностью основанных на кодах ответов] (https://meta.stackexchange.com/вопросы/114762/объяснения-entirely-% E2% 80% 8C% E2% 80% 8Bcode на основе-ответы) –