Java中如何将InputStream转换为String

19

2
你能详细说明一下吗?按照定义,流是无限的。除非有一些更多的限制条件,否则无法从无限流中获取一个固定大小的字符串。 - Thomas Owens
2
这个问题已经被问了很多次:https://dev59.com/WXI-5IYBdhLWcg3wm5zN - bakkal
https://dev59.com/UHVC5IYBdhLWcg3wZwJT - Patrick Kafka
如何使用nio FileChannel 进行操作:https://dev59.com/qnRC5IYBdhLWcg3wVvnL - x4u
这里有一个很棒的解决方案:将InputStream读取/转换为String - Richard Le Mesurier
6个回答

12

这是对Gopi答案的修改版本,它没有行尾问题,而且更有效,因为它不需要为每一行创建临时String对象,并避免了BufferedReader中的冗余复制和readLine()中的额外工作。

public static String convertStreamToString( InputStream is, String ecoding ) throws IOException
{
    StringBuilder sb = new StringBuilder( Math.max( 16, is.available() ) );
    char[] tmp = new char[ 4096 ];

    try {
       InputStreamReader reader = new InputStreamReader( is, ecoding );
       for( int cnt; ( cnt = reader.read( tmp ) ) > 0; )
            sb.append( tmp, 0, cnt );
    } finally {
        is.close();
    }
    return sb.toString();
}

1
+1 更加合理的编码处理。 - tc.

6
您需要构建一个InputStreamReader来包装输入流,将二进制数据和文本之间进行转换。根据您的输入源指定适当的编码方式。
一旦您拥有了一个InputStreamReader,您可以创建一个BufferedReader并逐行读取内容,或者只是逐个缓冲区读取并附加到StringBuilder中,直到read()调用返回-1。 Guava库使得第二部分变得容易 - 使用CharStreams.toString(inputStreamReader)

我从未尝试过这个,但在执行此操作之前,您不应该了解流代表什么吗?如果您有一个这样的流,使得read()永远不会返回-1,则甚至尝试此操作也没有价值。但是,与此同时,我想不出一种从头脑中消失的流。 - Thomas Owens
1
@Thomas:嗯,你可以轻松地创建一个仅提供随机数字的流。我假设这个问题是在一个实际上有“读取流到末尾”的概念的情况下被问出来的... - Jon Skeet

5

以下是从这里改编的示例代码。

public  String convertStreamToString(InputStream is) throws IOException {
        /*
         * To convert the InputStream to String we use the BufferedReader.readLine()
         * method. We iterate until the BufferedReader return null which means
         * there's no more data to read. Each line will appended to a StringBuilder
         * and returned as String.
         */
        if (is != null) {
            StringBuilder sb = new StringBuilder();
            String line;

            try {
               BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                while ((line = reader.readLine()) != null) {
                    sb.append(line).append("\n");
                }
            } finally {
                is.close();
            }
            return sb.toString();
        } else {       
            return "";
        }
    }

2
请注意,这将规范化行尾符号 - 它不一定会返回完全相同的原始文本数据。 - Jon Skeet
编辑代码以纳入您的建议。返回翻译后的文本:true。 - Gopi
现在它将完全不包括行尾。我认为Jon Skeet只是在说每个行尾\r\n(或\r)都变成了\n - Justin Ardini
啊啊啊,谢谢您提醒。已还原。 - Gopi

5

作为一名软件工程师,我喜欢这个。重用现有的库来完成工作。Apache Commons(以及所有的Apache项目)都做得非常好,在许多情况下非常有帮助。 - Thomas Owens
请注意,使用上述方法会使用平台的默认编码,即结果取决于用户设置或其他外部因素。大多数情况下,最好使用一个带有编码作为附加参数的方法。可以参考这个相关问题的评论。Apaches IOUtils 也提供了类似的方法。顺便说一句,Javadoc 的链接已经失效了... - siegi

2
你也可以像下面这样使用 StringWriter;每次从 InputStream 中读取时,都会与 StringWriter 的 write(或 append)匹配,在完成后,你可以调用 getBuffer 来获取一个 StringBuffer,该 StringBuffer 可以直接使用,或者你可以调用它的 toString 方法。

1
将流包装在Reader中以进行区域设置转换,然后在StringBuffer中收集时继续读取。完成后,在StringBuffer上执行toString()。

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