private static final int BUFFER_SIZE = 4 * 1024;
public static String inputStreamToString(InputStream inputStream, String charsetName)
throws IOException {
StringBuilder builder = new StringBuilder();
InputStreamReader reader = new InputStreamReader(inputStream, charsetName);
char[] buffer = new char[BUFFER_SIZE];
int length;
while ((length = reader.read(buffer)) != -1) {
builder.append(buffer, 0, length);
}
return builder.toString();
}
11
这是一种仅使用标准Java库的方法(注意流未关闭,YMMV) .
static String convertStreamToString(java.io.InputStream is) {
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
我从"Stupid Scanner tricks"文章中学到了这个技巧 . 它起作用的原因是Scanner迭代流中的标记,在这种情况下,我们使用"beginning of the input boundary"(\ A)分隔标记,因此只为流的整个内容提供一个标记 .
Note, if you need to be specific about the input stream's encoding, you can provide the second argument to Scanner constructor that indicates what charset to use (e.g. "UTF-8").
public static String slurp(final InputStream is, final int bufferSize) {
final char[] buffer = new char[bufferSize];
final StringBuilder out = new StringBuilder();
try (Reader in = new InputStreamReader(is, "UTF-8")) {
for (;;) {
int rsz = in.read(buffer, 0, buffer.length);
if (rsz < 0)
break;
out.append(buffer, 0, rsz);
}
}
catch (UnsupportedEncodingException ex) {
/* ... */
}
catch (IOException ex) {
/* ... */
}
return out.toString();
}
11
这是我在经过一些实验后想出的最优雅的纯Java(无库)解决方案:
public static String fromStream(InputStream in) throws IOException
{
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder out = new StringBuilder();
String newLine = System.getProperty("line.separator");
String line;
while ((line = reader.readLine()) != null) {
out.append(line);
out.append(newLine);
}
return out.toString();
}
28
如果使用Stream Readers,请务必在结尾处关闭流
private String readStream(InputStream iStream) throws IOException {
//build a Stream Reader, it can read char by char
InputStreamReader iStreamReader = new InputStreamReader(iStream);
//build a buffered Reader, so that i can read whole line at once
BufferedReader bReader = new BufferedReader(iStreamReader);
String line = null;
StringBuilder builder = new StringBuilder();
while((line = bReader.readLine()) != null) { //Read till end
builder.append(line);
builder.append("\n"); // append new line to preserve lines
}
bReader.close(); //close all opened stuff
iStreamReader.close();
//iStream.close(); //EDIT: Let the creator of the stream close it!
// some readers may auto close the inner stream
return builder.toString();
}
编辑:在JDK 7上,您可以使用try-with-resources构造 .
/**
* Reads the stream into a string
* @param iStream the input stream
* @return the string read from the stream
* @throws IOException when an IO error occurs
*/
private String readStream(InputStream iStream) throws IOException {
//Buffered reader allows us to read line by line
try (BufferedReader bReader =
new BufferedReader(new InputStreamReader(iStream))){
StringBuilder builder = new StringBuilder();
String line;
while((line = bReader.readLine()) != null) { //Read till end
builder.append(line);
builder.append("\n"); // append new line to preserve lines
}
return builder.toString();
}
}
String result = new BufferedReader(new InputStreamReader(inputStream)).lines()
.parallel().collect(Collectors.joining("\n"));
使用 InputStreamReader 和 StringBuilder (JDK)
final int bufferSize = 1024;
final char[] buffer = new char[bufferSize];
final StringBuilder out = new StringBuilder();
Reader in = new InputStreamReader(inputStream, "UTF-8");
for (; ; ) {
int rsz = in.read(buffer, 0, buffer.length);
if (rsz < 0)
break;
out.append(buffer, 0, rsz);
}
return out.toString();
使用 StringWriter 和 IOUtils.copy (Apache Commons)
StringWriter writer = new StringWriter();
IOUtils.copy(inputStream, writer, "UTF-8");
return writer.toString();
使用 ByteArrayOutputStream 和 inputStream.read (JDK)
ByteArrayOutputStream result = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1) {
result.write(buffer, 0, length);
}
// StandardCharsets.UTF_8.name() > JDK 7
return result.toString("UTF-8");
public static String convertStreamToString(InputStream is) {
if (is == null) return null;
StringBuilder sb = new StringBuilder(2048); // Define a size if you have an idea of it.
char[] read = new char[128]; // Your buffer size.
try (InputStreamReader ir = new InputStreamReader(is, StandardCharsets.UTF_8)) {
for (int i; -1 != (i = ir.read(read)); sb.append(read, 0, i));
} catch (Throwable t) {}
return sb.toString();
}
15
这里是或多或少的sampath的答案,清理了一下并表示为一个函数:
String streamToString(InputStream in) throws IOException {
StringBuilder out = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
for(String line = br.readLine(); line != null; line = br.readLine())
out.append(line);
br.close();
return out.toString();
}
2159
为了完整性,这里是 Java 9 解决方案:
public static String toString(InputStream input) throws IOException {
return new String(input.readAllBytes(), StandardCharsets.UTF_8);
}
30 回答
JDK中最简单的方法是使用以下代码snipplet .
如果您喜欢冒险,可以将Scala和Java混合使用,最后得到:
混合Java和Scala代码和库有它的好处 .
看这里的完整描述:Idiomatic way to convert an InputStream to a String in Scala
Kotlin用户只需:
而
是Kotlin标准库的内置扩展方法 .
这是我的基于 Java 8 的解决方案,它使用新的Stream API来收集来自
InputStream
的所有行:In Groovy
对于那些想要实现apache但不想要整个库的人来说,这是一个改编自
org.apache.commons.io.IOUtils
source code的答案 .这是一种仅使用标准Java库的方法(注意流未关闭,YMMV) .
我从"Stupid Scanner tricks"文章中学到了这个技巧 . 它起作用的原因是Scanner迭代流中的标记,在这种情况下,我们使用"beginning of the input boundary"(\ A)分隔标记,因此只为流的整个内容提供一个标记 .
Note, if you need to be specific about the input stream's encoding, you can provide the second argument to Scanner constructor that indicates what charset to use (e.g. "UTF-8").
帽子小贴士也去了Jacob,曾经指出我的文章 .
EDITED: 感谢Patrick的建议,在处理空输入流时使函数更加健壮 . One more edit: nixed try / catch,帕特里克的方式更简洁 .
这是在不使用任何第三方库的情况下将
InputStream
转换为String
的完整方法 . 使用StringBuilder
用于单线程环境,否则使用StringBuffer
.怎么样:
另一个,适用于所有Spring用户:
org.springframework.util.StreamUtils
中的实用程序方法与FileCopyUtils
中的实用程序方法类似,但它们在完成后将流保持打开状态 .如果您不能使用Commons IO(FileUtils / IOUtils / CopyUtils),这是一个使用BufferedReader逐行读取文件的示例:
或者如果你想要原始速度,我建议改变Paul de Vrieze的建议(避免使用StringWriter(在内部使用StringBuffer):
使用Stream的纯Java解决方案,自Java 8开始工作 .
正如ChristofferHammarström在other answer下面所提到的,明确指定Charset更安全 . 即InputStreamReader构造函数可以更改如下:
这个怎么样?
一个很好的方法是使用Apache commons
IOUtils
将InputStream
复制到StringWriter
...类似于甚至
或者,如果您不想混合Streams和Writers,可以使用
ByteArrayOutputStream
考虑到文件一应首先获得
java.io.Reader
实例 . 然后可以将其读取并添加到StringBuilder
(如果我们不在多个线程中访问它,我们不需要StringBuffer
,并且StringBuilder
更快) . 这里的诀窍是我们在块中工作,因此不需要其他缓冲流 . 块大小参数化以用于运行时性能优化 .这是我在经过一些实验后想出的最优雅的纯Java(无库)解决方案:
如果使用Stream Readers,请务必在结尾处关闭流
编辑:在JDK 7上,您可以使用try-with-resources构造 .
使用Java 9中支持的java.io.InputStream.transferTo(OutputStream)和采用charset名称的ByteArrayOutputStream.toString(String):
总结其他答案我找到了11种主要方法(见下文) . 我写了一些性能测试(见下面的结果):
Ways to convert an InputStream to a String:
IOUtils.toString
(Apache Utils)CharStreams
( Guava )Scanner
(JDK)\r\n
)转换为\n
.\r\n
)转换为\n
.InputStreamReader
和StringBuilder
(JDK)StringWriter
和IOUtils.copy
(Apache Commons)ByteArrayOutputStream
和inputStream.read
(JDK)BufferedReader
(JDK) . Warning: 此解决方案将不同的换行符(如\n\r
)转换为line.separator
系统属性(例如,在Windows中转换为"\r\n") .BufferedInputStream
和ByteArrayOutputStream
(JDK)inputStream.read()
和StringBuilder
(JDK) . Warning :此解决方案存在Unicode问题,例如使用俄语文本(仅适用于非Unicode文本)Warning :
解决方案4,5和9将不同的换行符转换为一个换行符 .
解决方案11无法与Unicode文本一起正常工作
Performance tests
小
String
(长度= 175)的性能测试,github的url(模式=平均时间,系统= Linux,得分1,343是最好的):大
String
(长度= 50100)的性能测试,github的url(模式=平均时间,系统= Linux,得分200,715是最好的):图表(性能测试取决于Windows 7系统中的输入流长度)
性能测试(平均时间)取决于Windows 7系统中的输入流长度:
我经常进行一些计时测试,因为时间很重要 .
我试图以不同的方式将响应变为String 3 . (如下所示)
为了便于阅读,我遗漏了try / catch块 .
为了给出上下文,这是所有3种方法的前面的代码:
1)
2)
3)
因此,在使用相同的请求/响应数据对每个方法运行500次测试之后,这里是数字 . 再一次,这些是我的发现,你的发现可能不完全相同,但我写这篇文章是为了向其他人说明这些方法的效率差异 .
排名:
方法#1
方法#3 - 比#1慢2.6%
方法#2 - 比#1慢4.3%
这些方法中的任何一种都是用于获取响应并从中创建String的适当解决方案 .
我会使用一些Java 8技巧 .
基本上和其他一些答案一样,除了更简洁 .
这个很好,因为:
Charset手部安全 .
您可以控制读取缓冲区大小 .
您可以设置构建器的长度,但可能不完全相同 .
没有库依赖项 .
适用于Java 7或更高版本 .
这是为了什么?
这里是或多或少的sampath的答案,清理了一下并表示为一个函数:
为了完整性,这里是 Java 9 解决方案:
readAllBytes目前处于JDK 9主代码库中,因此可能会出现在该版本中 . 您现在可以使用JDK 9 snapshot builds进行尝试 .
这是我的纯Java和Android解决方案,效果很好......
以下是使用字节数组缓冲区仅使用JDK的方法 . 这实际上是commons-io
IOUtils.copy()
方法的工作原理 . 如果您从Reader
而不是InputStream
进行复制,则可以将byte[]
替换为char[]
.就
reduce
和concat
而言,它可以在Java 8中表示为:我在这里做了14个不同答案的基准测试(很抱歉没有提供学分但有太多重复)
结果非常令人惊讶 . 事实证明,Apache IOUtils 是最慢的,
ByteArrayOutputStream
是最快的解决方案:所以首先这里是最好的方法:
基准测试结果,20个循环中的20MB随机字节
时间(以毫秒为单位)
ByteArrayOutputStreamTest:194
NioStream:198
Java9ISTransferTo:201
Java9ISReadAllBytes:205
BufferedInputStreamVsByteArrayOutputStream:314
ApacheStringWriter2:574
GuavaCharStreams:589
ScannerReaderNoNextTest:614
ScannerReader:633
ApacheStringWriter:1544
StreamApi:错误
ParallelStreamApi:错误
BufferReaderTest:错误
InputStreamAndStringBuilder:错误
基准源代码
如果您使用的是Google-Collections / Guava,则可以执行以下操作:
请注意,
InputStreamReader
的第二个参数(即Charsets.UTF_8)不是必需的,但如果您知道它,通常最好指定编码(您应该这样做!)Apache Commons允许:
当然,您可以选择除UTF-8之外的其他字符编码 .
另见:(Docs)