如果您有java.io.InputStream对象,应该如何处理该对象并生成String?
假设我有一个包含文本数据的InputStream,我想将其转换为String,例如,我可以将其写入日志文件。
获取InputStream并将其转换为字符串的最简单方法是什么?
public String convertStreamToString(InputStream is) {
// ???
}
如果您有java.io.InputStream对象,应该如何处理该对象并生成String?
假设我有一个包含文本数据的InputStream,我想将其转换为String,例如,我可以将其写入日志文件。
获取InputStream并将其转换为字符串的最简单方法是什么?
public String convertStreamToString(InputStream is) {
// ???
}
当前回答
使用java 9中支持的java.io.InputStream.transferTo(OutputStream)和ByteArrayOutputStream.toString(String),该字符串采用字符集名称:
public static String gobble(InputStream in, String charsetName) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
in.transferTo(bos);
return bos.toString(charsetName);
}
其他回答
我已经写了一个这样的课,所以我想我会和大家分享。有时候,您不想仅仅为了一件事而添加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);
}
}
}
如果不能使用Commons IO(FileUtils/IOUtils/CopyUtils),下面是一个使用BufferedReader逐行读取文件的示例:
public class StringFromFile {
public static void main(String[] args) /*throws UnsupportedEncodingException*/ {
InputStream is = StringFromFile.class.getResourceAsStream("file.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(is/*, "UTF-8"*/));
final int CHARS_PER_PAGE = 5000; //counting spaces
StringBuilder builder = new StringBuilder(CHARS_PER_PAGE);
try {
for(String line=br.readLine(); line!=null; line=br.readLine()) {
builder.append(line);
builder.append('\n');
}
}
catch (IOException ignore) { }
String text = builder.toString();
System.out.println(text);
}
}
或者,如果你想要原始速度,我会根据Paul de Vrieze的建议(避免使用StringWriter(内部使用StringBuffer))提出一个变体:
public class StringFromFileFast {
public static void main(String[] args) /*throws UnsupportedEncodingException*/ {
InputStream is = StringFromFileFast.class.getResourceAsStream("file.txt");
InputStreamReader input = new InputStreamReader(is/*, "UTF-8"*/);
final int CHARS_PER_PAGE = 5000; //counting spaces
final char[] buffer = new char[CHARS_PER_PAGE];
StringBuilder output = new StringBuilder(CHARS_PER_PAGE);
try {
for(int read = input.read(buffer, 0, buffer.length);
read != -1;
read = input.read(buffer, 0, buffer.length)) {
output.append(buffer, 0, read);
}
} catch (IOException ignore) { }
String text = output.toString();
System.out.println(text);
}
}
嗯,你可以自己编程。。。这并不复杂。。。
String Inputstream2String (InputStream is) throws IOException
{
final int PKG_SIZE = 1024;
byte[] data = new byte [PKG_SIZE];
StringBuilder buffer = new StringBuilder(PKG_SIZE * 10);
int size;
size = is.read(data, 0, data.length);
while (size > 0)
{
String str = new String(data, 0, size);
buffer.append(str);
size = is.read(data, 0, data.length);
}
return buffer.toString();
}
以下内容并没有回答最初的问题,而是回答了一些问题。
几个回答暗示了这种形式的循环
String line = null;
while((line = reader.readLine()) != null) {
// ...
}
or
for(String line = reader.readLine(); line != null; line = reader.readLine()) {
// ...
}
第一种形式通过在封闭作用域中声明一个变量“read”来污染封闭作用域的命名空间,该变量不会用于for循环之外的任何内容。第二个表单重复readline()调用。
这里有一种用Java编写这种循环的更简洁的方法。事实证明,for循环中的第一个子句不需要实际的初始值设定项值。这将变量“line”的范围保持在for循环的主体内。更优雅!我在任何地方都没有看到有人使用这个表单(几年前的一天我随机发现了它),但我一直在使用它。
for (String line; (line = reader.readLine()) != null; ) {
//...
}
我在这里对14个不同的答案做了一个基准测试(很抱歉没有提供学分,但有太多重复)。
结果非常令人惊讶。事实证明,Apache IOUtils是最慢的解决方案,ByteArrayOutputStream是最快的解决方案:
因此,首先是最好的方法:
public String inputStreamToString(InputStream inputStream) throws IOException {
try(ByteArrayOutputStream result = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1) {
result.write(buffer, 0, length);
}
return result.toString(UTF_8);
}
}
20个周期内20 MB随机字节的基准结果
时间(毫秒)
字节数组输出流测试:194NioStream:198Java9ISTransferTo:201Java9ISReadAllBytes:205缓冲输入流VsByteArray输出流:314ApacheStringWriter2:574GuavaCharStreams:589扫描仪读取器无下一测试:614扫描仪读数:633ApacheStringWriter:1544StreamApi:错误ParallelStreamApi:错误BufferReaderTest:错误InputStreamAndStringBuilder:错误
基准源代码
import com.google.common.io.CharStreams;
import org.apache.commons.io.IOUtils;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
/**
* Created by Ilya Gazman on 2/13/18.
*/
public class InputStreamToString {
private static final String UTF_8 = "UTF-8";
public static void main(String... args) {
log("App started");
byte[] bytes = new byte[1024 * 1024];
new Random().nextBytes(bytes);
log("Stream is ready\n");
try {
test(bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void test(byte[] bytes) throws IOException {
List<Stringify> tests = Arrays.asList(
new ApacheStringWriter(),
new ApacheStringWriter2(),
new NioStream(),
new ScannerReader(),
new ScannerReaderNoNextTest(),
new GuavaCharStreams(),
new StreamApi(),
new ParallelStreamApi(),
new ByteArrayOutputStreamTest(),
new BufferReaderTest(),
new BufferedInputStreamVsByteArrayOutputStream(),
new InputStreamAndStringBuilder(),
new Java9ISTransferTo(),
new Java9ISReadAllBytes()
);
String solution = new String(bytes, "UTF-8");
for (Stringify test : tests) {
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {
String s = test.inputStreamToString(inputStream);
if (!s.equals(solution)) {
log(test.name() + ": Error");
continue;
}
}
long startTime = System.currentTimeMillis();
for (int i = 0; i < 20; i++) {
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {
test.inputStreamToString(inputStream);
}
}
log(test.name() + ": " + (System.currentTimeMillis() - startTime));
}
}
private static void log(String message) {
System.out.println(message);
}
interface Stringify {
String inputStreamToString(InputStream inputStream) throws IOException;
default String name() {
return this.getClass().getSimpleName();
}
}
static class ApacheStringWriter implements Stringify {
@Override
public String inputStreamToString(InputStream inputStream) throws IOException {
StringWriter writer = new StringWriter();
IOUtils.copy(inputStream, writer, UTF_8);
return writer.toString();
}
}
static class ApacheStringWriter2 implements Stringify {
@Override
public String inputStreamToString(InputStream inputStream) throws IOException {
return IOUtils.toString(inputStream, UTF_8);
}
}
static class NioStream implements Stringify {
@Override
public String inputStreamToString(InputStream in) throws IOException {
ReadableByteChannel channel = Channels.newChannel(in);
ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 16);
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(UTF_8);
}
}
static class ScannerReader implements Stringify {
@Override
public String inputStreamToString(InputStream is) throws IOException {
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
}
static class ScannerReaderNoNextTest implements Stringify {
@Override
public String inputStreamToString(InputStream is) throws IOException {
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
return s.next();
}
}
static class GuavaCharStreams implements Stringify {
@Override
public String inputStreamToString(InputStream is) throws IOException {
return CharStreams.toString(new InputStreamReader(
is, UTF_8));
}
}
static class StreamApi implements Stringify {
@Override
public String inputStreamToString(InputStream inputStream) throws IOException {
return new BufferedReader(new InputStreamReader(inputStream))
.lines().collect(Collectors.joining("\n"));
}
}
static class ParallelStreamApi implements Stringify {
@Override
public String inputStreamToString(InputStream inputStream) throws IOException {
return new BufferedReader(new InputStreamReader(inputStream)).lines()
.parallel().collect(Collectors.joining("\n"));
}
}
static class ByteArrayOutputStreamTest implements Stringify {
@Override
public String inputStreamToString(InputStream inputStream) throws IOException {
try(ByteArrayOutputStream result = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1) {
result.write(buffer, 0, length);
}
return result.toString(UTF_8);
}
}
}
static class BufferReaderTest implements Stringify {
@Override
public String inputStreamToString(InputStream inputStream) throws IOException {
String newLine = System.getProperty("line.separator");
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder result = new StringBuilder(UTF_8);
String line;
boolean flag = false;
while ((line = reader.readLine()) != null) {
result.append(flag ? newLine : "").append(line);
flag = true;
}
return result.toString();
}
}
static class BufferedInputStreamVsByteArrayOutputStream implements Stringify {
@Override
public String inputStreamToString(InputStream inputStream) throws IOException {
BufferedInputStream bis = new BufferedInputStream(inputStream);
ByteArrayOutputStream buf = new ByteArrayOutputStream();
int result = bis.read();
while (result != -1) {
buf.write((byte) result);
result = bis.read();
}
return buf.toString(UTF_8);
}
}
static class InputStreamAndStringBuilder implements Stringify {
@Override
public String inputStreamToString(InputStream inputStream) throws IOException {
int ch;
StringBuilder sb = new StringBuilder(UTF_8);
while ((ch = inputStream.read()) != -1)
sb.append((char) ch);
return sb.toString();
}
}
static class Java9ISTransferTo implements Stringify {
@Override
public String inputStreamToString(InputStream inputStream) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
inputStream.transferTo(bos);
return bos.toString(UTF_8);
}
}
static class Java9ISReadAllBytes implements Stringify {
@Override
public String inputStreamToString(InputStream inputStream) throws IOException {
return new String(inputStream.readAllBytes(), UTF_8);
}
}
}