如果您有java.io.InputStream对象,应该如何处理该对象并生成String?


假设我有一个包含文本数据的InputStream,我想将其转换为String,例如,我可以将其写入日志文件。

获取InputStream并将其转换为字符串的最简单方法是什么?

public String convertStreamToString(InputStream is) {
// ???
}

当前回答

这个问题的解决方案不是最简单的,但由于没有提到NIO流和通道,这里有一个使用NIO通道和ByteBuffer将流转换为字符串的版本。

public static String streamToStringChannel(InputStream in, String encoding, int bufSize) throws IOException {
    ReadableByteChannel channel = Channels.newChannel(in);
    ByteBuffer byteBuffer = ByteBuffer.allocate(bufSize);
    ByteArrayOutputStream bout = new ByteArrayOutputStream();
    WritableByteChannel outChannel = Channels.newChannel(bout);
    while (channel.read(byteBuffer) > 0 || byteBuffer.position() > 0) {
        byteBuffer.flip();  //make buffer ready for write
        outChannel.write(byteBuffer);
        byteBuffer.compact(); //make buffer ready for reading
    }
    channel.close();
    outChannel.close();
    return bout.toString(encoding);
}

下面是如何使用它的示例:

try (InputStream in = new FileInputStream("/tmp/large_file.xml")) {
    String x = streamToStringChannel(in, "UTF-8", 1);
    System.out.println(x);
}

对于大型文件,此方法的性能应该很好。

其他回答

一个很好的方法是使用Apache Commons IOUItils将InputStream复制到StringWriter中。。。类似于

StringWriter writer = new StringWriter();
IOUtils.copy(inputStream, writer, encoding);
String theString = writer.toString();

甚至

// NB: does not close inputStream, you'll have to use try-with-resources for that
String theString = IOUtils.toString(inputStream, encoding);

或者,如果不想混合流和写入器,可以使用ByteArrayOutputStream。

考虑到文件,首先应该获得java.io.Reader实例。然后可以将其读取并添加到StringBuilder中(如果我们不在多个线程中访问StringBuffer,我们就不需要StringBuffer了,StringBuilder速度更快)。这里的技巧是我们在块中工作,因此不需要其他缓冲流。块大小被参数化以用于运行时性能优化。

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

如果使用流读取器,请确保在结束时关闭流

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

编辑:在JDK7+上,可以使用trywithresources构造。

/**
 * 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();
    }
}

与Okio一起:

String result = Okio.buffer(Okio.source(inputStream)).readUtf8();

注意:这可能不是个好主意。此方法使用递归,因此将非常快地命中StackOverflowError:

public String read (InputStream is) {
    byte next = is.read();
    return next == -1 ? "" : next + read(is); // Recursive part: reads next byte recursively
}