If you have java.io.InputStream
object, how should you process that object and produce a String
?
Suppose I have an InputStream
that contains text data, and I want to convert this to a String
(for example, so I can write the contents of the stream to a log file).
What is the easiest way to take the InputStream
and convert it to a String
?
public String convertStreamToString(InputStream is) {
// ???
}
Source: Tips4all
A nice way to do this is using Apache commons IOUtils to copy the InputStream into a StringWriter... something like
ReplyDeleteStringWriter writer = new StringWriter();
IOUtils.copy(inputStream, writer, encoding);
String theString = writer.toString();
Alternatively, you could use ByteArrayOutputStream if you don't want to mix your Streams and Writers
Here's a way using only standard Java library.
ReplyDeletepublic String convertStreamToString(java.io.InputStream is) {
try {
return new java.util.Scanner(is).useDelimiter("\\A").next();
} catch (java.util.NoSuchElementException e) {
return "";
}
}
I learned this trick from "Stupid Scanner tricks" article. The reason it works is because Scanner iterates over tokens in the stream, and in this case we separate tokens using "beginning of the input boundary" (\A) thus giving us only one token for the entire contents of the stream.
Note, if you need to be specific about the input stream's encoding, you can provide the second argument to Scanner ctor that indicates what charset to use (e.g. "UTF-8").
Hat tip goes also to Jacob, who once pointed me to the said article.
EDITED: Thanks to a suggestion from Patrick, made the function more robust when handling an empty input stream.
Apache commons allows:
ReplyDeleteString myString = IOUtils.toString(myInputStream, "UTF-8");
?
Of course, you could choose other character encodings besides UTF-8.
Also see:
http://commons.apache.org/io/api-1.4/org/apache/commons/io/IOUtils.html#toString(java.io.InputStream,%20java.lang.String)
Taking into account file one should first get a java.io.Reader instance. This can then be read and added to a StringBuilder (we don't need StringBuffer if we are not accessing it in multiple threads, and StringBuilder is faster). The trick here is that we work in blocks, and as such don't need other buffering streams. The block now is 64k, but it could be increased in size for a bit of performance gain.
ReplyDeletefinal char[] buffer = new char[0x10000];
StringBuilder out = new StringBuilder();
Reader in = new InputStreamReader(is, "UTF-8");
try {
int read;
do {
read = in.read(buffer, 0, buffer.length);
if (read>0) {
out.append(buffer, 0, read);
}
} while (read>=0);
} finally {
in.close();
}
String result = out.toString();
How about this?
ReplyDeleteInputStream in = /* your InputStream */;
InputStreamReader is = new InputStreamReader(in);
BufferedReader br = new BufferedReader(is);
String read = br.readLine();
while(read != null) {
System.out.println(read);
read = br.readLine();
}
If you are using Google-Collections/Guava you could do the following:
ReplyDeleteInputStream stream = ...
String content = CharStreams.toString(new InputStreamReader(stream));
How about:
ReplyDeleteimport java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;
public static String readInputStreamAsString(InputStream in)
throws IOException {
BufferedInputStream bis = new BufferedInputStream(in);
ByteArrayOutputStream buf = new ByteArrayOutputStream();
int result = bis.read();
while(result != -1) {
byte b = (byte)result;
buf.write(b);
result = bis.read();
}
return buf.toString();
}
If you can't use Commons IO (FileUtils/IOUtils/CopyUtils) here's an example using a BufferedReader to read the file line by line:
ReplyDeletepublic 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);
}
}
or if you want raw speed I'd propose a variation on what Paul de Vrieze suggested (which avoids using a StringWriter (which uses a StringBuffer internally) :
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);
}
}
As an alternative to the Commons libraries, Google's excellent guava-libraries let you do this fairly concisely; given an InputStream named inputStream:
ReplyDeleteimport com.google.common.io.CharStreams;
CharStreams.toString( new InputStreamReader( inputStream ));
I ran some timing tests because time matters, always.
ReplyDeleteI attempted to get the response into a String 3 different ways. (shown below)
I left out try/catch blocks for the sake readability.
To give context, this is the preceding code for all 3 approaches:
String response;
String url = "www.blah.com/path?key=value";
GetMethod method = new GetMethod(url);
int status = client.executeMethod(method);
1)
response = method.getResponseBodyAsString();
2)
InputStream resp = method.getResponseBodyAsStream();
InputStreamReader is=new InputStreamReader(resp);
BufferedReader br=new BufferedReader(is);
String read = null;
StringBuffer sb = new StringBuffer(read);
while((read = br.readLine()) != null) {
sb.append(read);
}
response = sb.toString();
3)
InputStream iStream = method.getResponseBodyAsStream();
StringWriter writer = new StringWriter();
IOUtils.copy(iStream, writer, "UTF-8");
response = writer.toString();
So, after running 500 tests on each approach with the same request/response data, here are the numbers. Once again, these are my findings and your findings may not be exactly the same, but I wrote this to give some indication to others of the efficiency differences of these approaches.
Ranks:
Approach #1
Approach #3 - 2.6% slower than #1
Approach #2 - 4.3% slower than #1
Any of these approaches is an appropriate solution to the grabbing a response and creating a String from it.
If you were feeling adventurous, you could mix Scala and Java and end up with this:
ReplyDeletescala.io.Source.fromInputStream(is).mkString("")
Mixing Java and Scala code and libraries has it's benefits.
See full description here: Idiomatic way to convert an InputStream to a String in Scala
Here's more-or-less sampath's answer, cleaned up a bit and represented as a function:
ReplyDeleteString streamToString(InputStream in) throws IOException {
String out = new String();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
for(String line = br.readLine(); line != null; line = br.readLine())
out += line;
return out;
}
First ,you have to know the encoding of string that you want to convert.Because the java.io.InputStream operates an underlying array of bytes,however,a string is composed by a array of character that needs an encoding, e,g. UTF-8,the JDK will take the default encoding that is taken from System.getProperty("file.encoding","UTF-8");
ReplyDeletebyte[] bytes=new byte[inputStream.available()];
inputStream.read(bytes);
String s = new String(bytes);
If inputStream's byte array is very big, you could do it in loop.
:EOF
private String readFully(InputStream inputStream)
ReplyDeletethrows IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length = 0;
while ((length = inputStream.read(buffer)) != -1) {
baos.write(buffer, 0, length);
}
return new String(baos.toByteArray());
}
Try this one as well
ReplyDeleteStringBuilder response = new StringBuilder();
int value = 0;
boolean active = true;
while (active) {
value = is.read();
if (value == -1) {
throw new IOException("End of Stream");
} else if (value != '\n') {
response.append((char) value);
continue;
} else {
active = false;
}
}
return response.toString();