使用流数据中给定的编码将InputStream转换为String

3

我的输入是一个包含XML文档的InputStream。XML中使用的编码方式未知,定义在XML文档的第一行中。我想把这个InputStream中的所有文档都转换成一个String。

为了做到这一点,我使用了BufferedInputStream来标记文件的开头,并开始读取第一行。我读取这个第一行来获取编码方式,然后使用InputStreamReader生成一个带有正确编码的String。

似乎这不是实现这个目标的最佳方法,因为它会产生OutOfMemory错误。

有什么好的想法吗?

public static String streamToString(final InputStream is) {
    String result = null;

    if (is != null) {
        BufferedInputStream bis = new BufferedInputStream(is);
        bis.mark(Integer.MAX_VALUE);
        final StringBuilder stringBuilder = new StringBuilder();
        try {
            // stream reader that handle encoding
            final InputStreamReader readerForEncoding = new InputStreamReader(bis, "UTF-8");
            final BufferedReader bufferedReaderForEncoding = new BufferedReader(readerForEncoding);

            String encoding = extractEncodingFromStream(bufferedReaderForEncoding);
            if (encoding == null) {
                encoding = DEFAULT_ENCODING;
            }

            // stream reader that handle encoding
            bis.reset();
            final InputStreamReader readerForContent = new InputStreamReader(bis, encoding);
            final BufferedReader bufferedReaderForContent = new BufferedReader(readerForContent);

            String line = bufferedReaderForContent.readLine();
            while (line != null) {
                stringBuilder.append(line); 
                line  = bufferedReaderForContent.readLine();
            } 
            bufferedReaderForContent.close();
            bufferedReaderForEncoding.close();
        } catch (IOException e) { 
            // reset string builder
            stringBuilder.delete(0, stringBuilder.length());
        }  
        result = stringBuilder.toString();
    }else {
        result = null;
    }
    return result;
}
2个回答

2

调用mark(Integer.MAX_VALUE)导致了OutOfMemoryError的发生,因为它试图分配2GB的内存。

您可以通过使用迭代方法来解决这个问题。将标记readLimit设置为合理的值,比如8K。在99%的情况下,这将起作用,但在一些严重的情况下,例如在声明中属性之间有16K的空格,您需要再试一次。因此,有一个循环来尝试找到编码,但如果它在给定的标记区域内找不到它,则会再次尝试,将请求的标记readLimit大小加倍。

为确保不超过标记限制,您应该自己读取InputStream,读取至标记限制为止,并将其读入一个字节数组。然后,您将字节数组包装在一个ByteArrayInputStream中,并将其传递给分配给“readerForEncoding”的InputStreamReader的构造函数。


0
你可以使用这个方法将输入流转换为字符串。这可能会对你有所帮助...
private String convertStreamToString(InputStream input) throws Exception{
    BufferedReader reader = new BufferedReader(new InputStreamReader(input));
    StringBuilder sb = new StringBuilder();
    String line = null;

    while ((line = reader.readLine()) != null) {
        sb.append(line);
    }

    input.close();
    return sb.toString();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接