50

我有一个很大的 CLOB(超过 32kB),我想使用 StringBuilder 将其读取到字符串中。我如何以最有效的方式做到这一点?我不能为 StringBuilder 使用“int length”构造函数,因为我的 CLOB 的长度比“int”长并且需要一个“long”值。

我对 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();
}
4

12 回答 12

52

好吧,我假设一个一般用途,首先你必须下载apache commons,在那里你会发现一个名为 IOUtils 的实用程序类,它有一个名为 copy() 的方法;

现在解决方案是:使用 getAsciiStream() 获取 CLOB 对象的输入流并将其传递给 copy() 方法。

InputStream in = clobObject.getAsciiStream();
StringWriter w = new StringWriter();
IOUtils.copy(in, w);
String clobAsString = w.toString();
于 2010-01-30T22:54:03.537 回答
32

有什么问题:

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

?

例如,Oracle在内部oracle.sql.CLOB执行,其中定义了并且只是和下一个包装到......你永远不会比.getSubString()char[]oracle.jdbc.driver.T4CConnectionSystem.arraycopy()StringSystem.arraycopy()

更新获取驱动ojdbc6.jar,反编译CLOB实现,并根据内部知识研究哪种情况可能更快。

于 2014-07-01T15:41:31.323 回答
21

我的回答只是一个味道。但是我通过序列化压缩内容对其进行了测试,并且可以正常工作。所以我可以相信这个解决方案,不像第一个提供的解决方案(使用 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();
}
于 2012-12-10T03:42:23.757 回答
20

我不能使用“int length”构造函数,StringBuilder因为我的 CLOB 的长度比 a 长int并且需要一个long值。

如果 CLOB 长度大于 int 的大小,则 CLOB 数据也不适合 String。您必须使用流式处理方法来处理如此多的 XML 数据。

如果 CLOB 的实际长度小于Integer.MAX_VALUE,只需将longint放在(int)前面即可。

于 2010-01-31T11:19:03.690 回答
4

如果您真的必须只使用标准库,那么您只需扩展 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 以获得更好的性能。
于 2010-01-31T12:09:56.020 回答
4

如果使用 Mule,以下是步骤。

请按照以下步骤操作。

在连接器中启用流式传输,即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 数据。

就是这样!

问候纳文

于 2016-04-13T14:35:53.760 回答
2

使用 apache commons.io 的友好帮助方法

Reader reader = clob.getCharacterStream();
StringWriter writer = new StringWriter();
IOUtils.copy(reader, writer);
String clobContent = writer.toString();
于 2018-07-31T13:06:04.073 回答
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;
}
于 2015-11-13T09:29:26.880 回答
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();
}

上述方法也非常有效。

于 2014-11-22T21:15:56.137 回答
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();
}
于 2017-12-04T10:11:37.197 回答
0
 public static String clobToString(final Clob clob) throws SQLException, IOException {
        try (final Reader reader = clob.getCharacterStream()) {
            try (final StringWriter stringWriter = new StringWriter()) {
                IOUtils.copy(reader, stringWriter);
                return stringWriter.toString();
            }
        }
    }
于 2021-01-12T17:57:06.157 回答
-2

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();
于 2016-01-05T10:51:41.317 回答