2010-01-30 39 views
30

我有一個很大的CLOB(超過32kB),我想使用StringBuilder讀取字符串。我如何以最有效的方式做到這一點?我無法使用StringBuilder的「int length」構造函數,因爲CLOB的長度比「int」長,需要一個「long」值。用於將CLOB讀入String的最有效解決方案,以及Java中用於CLOB的字符串的最有效解決方案?

我不喜歡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爲一個字符串到底該怎麼做? – 2010-01-30 22:38:34

+0

你是指數據庫意義上的CLOB,還是隻是「大字符串」? – skaffman 2010-01-30 22:41:45

+0

是的,它是來自DB2數據庫的CLOB。 – Jonas 2010-01-30 22:42:49

回答

13

因爲我CLOB的長度比int長,需要一個long值,我不能用「INT長度」的構造函數StringBuilder

如果CLOB長度大於適合int的值,那麼CLOB數據也不適合String。您必須使用流式方法來處理這麼多的XML數據。

如果CLOB的實際長度超過Integer.MAX_VALUE小,只是通過把(int)在它的前面迫使longint

+5

事實上,如果CLOB大小大於2^32字節,那麼您遇到了很大的問題 – skaffman 2010-01-31 11:55:01

+0

如果他需要整個CLOB來處理 – 2016-01-05 10:39:26

34

好,我會想一個通用,首先你要下載apache commons,在那裏你會找到一個實用工具類名爲IOUtils,它有一個名爲copy()的方法;

現在解決方案是:使用getAsciiStream()獲取CLOB對象的輸入流並將其傳遞給copy()方法。

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

謝謝,那看起來不錯。但是我更關注這個問題,因爲我更喜歡只使用標準庫的解決方案。 – Jonas 2010-01-31 09:46:57

+0

我已經加載了Apache Commons庫,所以這是一個完美的解決方案。謝謝!如果你使用unicode,getAsciiStream會給你帶來麻煩。 (或者任何超出ascii的字符) – 2011-06-02 14:47:03

+7

爲了防止編碼問題,我將'InputStream'改爲'Reader','clobObject.getAsciiStream()'改爲'clobObject.getCharacterStream()'。 – Dormouse 2014-06-11 07:52:03

2

如果您確實必須只使用標準庫,那麼您只需要擴展Omar的解決方案。 (Apache的IOUtils基本上是一套方便的方法,從而節省了大量的編碼)

你已經能夠通過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. 分別用BufferedReader和BufferedWriter包裝InputStreamReader和StringWriter以獲得更好的性能。
+0

看起來與我在我的代碼中提供的代碼類似問題,他們之間有沒有我看不到的關鍵區別?在性能角度的例子? – Jonas 2010-01-31 12:41:48

+0

糟糕,我錯過了你的代碼片段!它有點類似,但請記住,只需抓住BufferedReader.readLine(),就會錯過換行。 – 2010-02-01 00:36:32

+1

小修正行2應該是讀取器讀取= new InputStreamReader(in); – Vivek 2012-06-04 07:15:23

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.sql.CLOB使內部char[]getSubString()oracle.jdbc.driver.T4CConnection定義,只是System.arraycopy()和明年換到String ...你永遠不會得到更快的讀取然後System.arraycopy()

UPDATE獲取驅動ojdbc6.jar和反編譯CLOB落實,並研究這種情況下會更快基於內部知識。

+0

在字符串中留下大量換行符。 – Gervase 2014-09-16 19:58:29

+0

@Gervase Newlines在XML中可能很重要。無論如何,在將它存儲到數據庫之前,你應該修剪無用的空格和換行符。 – 2016-05-23 14:43:53

+0

需要清楚的幾點:如果clob.length()大於Integer.MAX_VALUE,會發生什麼情況?什麼是jar包含oracle.sql.CLOB? – Stephan 2016-05-26 14:33:24

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

,以下是步驟。

請按照以下步驟操作。

啓用流在所述連接器即progressiveStreaming = 2

類型轉換DB2返回到CLOB java.sql.Clob中(IBM支持這種類型的鑄造)

轉換,要字符流(ASCII流有時可能不支持一些特殊字符)。所以你可以使用getCharacterStream()

這將返回一個「reader」對象,它可以使用common-io(IOUtils)轉換爲「String」。

因此總之,使用groovy組件並添加下面的代碼。

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爲主,答案) – 2017-12-04 10:32:23