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


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

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

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

当前回答

我已经写了一个这样的课,所以我想我会和大家分享。有时候,您不想仅仅为了一件事而添加Apache Commons,并且想要比Scanner更笨的东西,它不检查内容。

用法如下

// Read from InputStream
String data = new ReaderSink(inputStream, Charset.forName("UTF-8")).drain();

// Read from File
data = new ReaderSink(file, Charset.forName("UTF-8")).drain();

// Drain input stream to console
new ReaderSink(inputStream, Charset.forName("UTF-8")).drainTo(System.out);

以下是ReaderSink的代码:

import java.io.*;
import java.nio.charset.Charset;

/**
 * A simple sink class that drains a {@link Reader} to a {@link String} or
 * to a {@link Writer}.
 *
 * @author Ben Barkay
 * @version 2/20/2014
 */
public class ReaderSink {
    /**
     * The default buffer size to use if no buffer size was specified.
     */
    public static final int DEFAULT_BUFFER_SIZE = 1024;

    /**
     * The {@link Reader} that will be drained.
     */
    private final Reader in;

    /**
     * Constructs a new {@code ReaderSink} for the specified file and charset.
     * @param file      The file to read from.
     * @param charset   The charset to use.
     * @throws FileNotFoundException    If the file was not found on the filesystem.
     */
    public ReaderSink(File file, Charset charset) throws FileNotFoundException {
        this(new FileInputStream(file), charset);
    }

    /**
     * Constructs a new {@code ReaderSink} for the specified {@link InputStream}.
     * @param in        The {@link InputStream} to drain.
     * @param charset   The charset to use.
     */
    public ReaderSink(InputStream in, Charset charset) {
        this(new InputStreamReader(in, charset));
    }

    /**
     * Constructs a new {@code ReaderSink} for the specified {@link Reader}.
     * @param in    The reader to drain.
     */
    public ReaderSink(Reader in) {
        this.in = in;
    }

    /**
     * Drains the data from the underlying {@link Reader}, returning a {@link String} containing
     * all of the read information. This method will use {@link #DEFAULT_BUFFER_SIZE} for
     * its buffer size.
     * @return  A {@link String} containing all of the information that was read.
     */
    public String drain() throws IOException {
        return drain(DEFAULT_BUFFER_SIZE);
    }

    /**
     * Drains the data from the underlying {@link Reader}, returning a {@link String} containing
     * all of the read information.
     * @param bufferSize    The size of the buffer to use when reading.
     * @return  A {@link String} containing all of the information that was read.
     */
    public String drain(int bufferSize) throws IOException {
        StringWriter stringWriter = new StringWriter();
        drainTo(stringWriter, bufferSize);
        return stringWriter.toString();
    }

    /**
     * Drains the data from the underlying {@link Reader}, writing it to the
     * specified {@link Writer}. This method will use {@link #DEFAULT_BUFFER_SIZE} for
     * its buffer size.
     * @param out   The {@link Writer} to write to.
     */
    public void drainTo(Writer out) throws IOException {
        drainTo(out, DEFAULT_BUFFER_SIZE);
    }

    /**
     * Drains the data from the underlying {@link Reader}, writing it to the
     * specified {@link Writer}.
     * @param out           The {@link Writer} to write to.
     * @param bufferSize    The size of the buffer to use when reader.
     */
    public void drainTo(Writer out, int bufferSize) throws IOException {
        char[] buffer = new char[bufferSize];
        int read;
        while ((read = in.read(buffer)) > -1) {
            out.write(buffer, 0, read);
        }
    }
}

其他回答

Apache Commons允许:

String myString = IOUtils.toString(myInputStream, "UTF-8");

当然,您可以选择UTF-8以外的其他字符编码。

另请参阅:(文档)

JDK 7/8应答,关闭流并仍然抛出IOException:

StringBuilder build = new StringBuilder();
byte[] buf = new byte[1024];
int length;
try (InputStream is = getInputStream()) {
  while ((length = is.read(buf)) != -1) {
    build.append(new String(buf, 0, length));
  }
}

在Groovy中

inputStream.getText()

基于已接受的Apache Commons答案的第二部分,但在始终关闭流的情况下填补了一个小缺口:

    String theString;
    try {
        theString = IOUtils.toString(inputStream, encoding);
    } finally {
        IOUtils.closeQuietly(inputStream);
    }

当输入流来自类路径资源(这似乎是一项流行任务)时,Guava提供了更短的高效自动关闭解决方案:

byte[] bytes = Resources.toByteArray(classLoader.getResource(path));

or

String text = Resources.toString(classLoader.getResource(path), StandardCharsets.UTF_8);

还有ByteSource和CharSource的一般概念,它们温和地负责打开和关闭流。

因此,例如,不要显式打开一个小文件来读取其内容:

String content = Files.asCharSource(new File("robots.txt"), StandardCharsets.UTF_8).read();
byte[] data = Files.asByteSource(new File("favicon.ico")).read();

或者只是

String content = Files.toString(new File("robots.txt"), StandardCharsets.UTF_8);
byte[] data = Files.toByteArray(new File("favicon.ico"));