用于将CLOB读取到String的最有效解决方案,以及在Java中将String读取到CLOB?

Jon*_*nas 43 java stringbuilder clob

我有一个很大的CLOB(超过32kB)我想用StringBuilder读取一个String.我如何以最有效的方式做到这一点?我不能使用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();
}
Run Code Online (Sandbox Code Playgroud)

Oma*_*bji 45

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

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

InputStream in = clobObject.getAsciiStream();
StringWriter w = new StringWriter();
IOUtils.copy(in, w);
String clobAsString = w.toString();
Run Code Online (Sandbox Code Playgroud)

  • 我将`InputStream`改为`Reader`和`clobObject.getAsciiStream()`改为`clobObject.getCharacterStream()`以防止编码问题. (12认同)
  • 如果你使用unicode,getAsciiStream会让你头疼.(或任何落在ascii之外的字符) (10认同)
  • `IOUtils.copy(in, w)` 已弃用,请使用 `IOUtils.copy(in, w, StandardCharsets.UTF_8)` 代替 (2认同)

Bar*_*end 19

我不能使用"int length"构造函数,StringBuilder因为我的CLOB长度比a长int,需要一个long值.

如果CLOB长度大于int中的值,则CLOB数据也不适合String.您将不得不使用流式处理方法来处理这么多的XML数据.

如果CLOB的实际长度小于Integer.MAX_VALUE,只是迫使longint通过把(int)在它前面.

  • 实际上,如果CLOB大小大于2 ^ 32字节,那么你就会遇到大问题 (8认同)

Sta*_*lov 19

我的答案只是一种相同的味道.但我通过序列化压缩内容来测试它并且它有效.所以我可以相信这个解决方案,不像第一个提供的解决方案(使用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();
}
Run Code Online (Sandbox Code Playgroud)


gav*_*koa 19

有什么不对:

clob.getSubString(1, (int) clob.length());
Run Code Online (Sandbox Code Playgroud)

例如,Oracle oracle.sql.CLOB执行getSubString()内部char[]定义的内部oracle.jdbc.driver.T4CConnection和刚刚System.arraycopy()和下一个包装String...你永远不会得到更快的阅读System.arraycopy().

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

  • @Gervase 换行符在 XML 中可能很重要。无论如何,在将其存储到数据库之前,您应该修剪无用的空格和换行符。 (2认同)
  • @Stephan我研究了`ojdbc6.jar`。Integer.MAX_VALUE是** JDK Platform 2 **的数组长度的限制,并且String在数组中保留字符。因此,对于2个GiB CLOB来说,您很不走运。尝试流式方法,因为您不能使用纯Java内存模型来保存该数据(除非您使用某些本机扩展和具有足够系统内存的64位平台)。 (2认同)

Edw*_*Lee 5

如果您确实必须仅使用标准库,那么您只需稍微扩展 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();
Run Code Online (Sandbox Code Playgroud)

请记住

  1. 如果您的 clob 包含的字符多于字符串所能容纳的字符,则此方法将不起作用。
  2. 分别用 BufferedReader 和 BufferedWriter 包装 InputStreamReader 和 StringWriter,以获得更好的性能。

  • 不不不。`getAsciiStream()` 强制使用 ASCII 编码并破坏所有非 ASCII 字符。您正在做的是从字符源获取“InputStream”(字节),然后立即使用“InputStreamReader”上的随机(平台默认)编码将它们转换回字符。这是一个冗余操作,除了它会损坏非 ASCII 数据之外。只需直接从“getCharacterStream()”“Reader”读取并写入“StringWriter”即可。 (2认同)