By Johnny Maelstrom


2008-11-21 16:47:40 8 Comments

If you have a 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 it to a String, so for example I can write that to a log file.

What is the easiest way to take the InputStream and convert it to a String?

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

30 comments

@czerny 2020-04-05 00:03:47

String inputStreamToString(InputStream inputStream, Charset charset) throws IOException {
    try (
            final StringWriter writer = new StringWriter();
            final InputStreamReader reader = new InputStreamReader(inputStream, charset)
        ) {
        reader.transferTo(writer);
        return writer.toString();
    }
}

@Viacheslav Vedenin 2016-02-17 00:58:48

Summarize other answers I found 11 main ways to do this (see below). And I wrote some performance tests (see results below):

Ways to convert an InputStream to a String:

  1. Using IOUtils.toString (Apache Utils)

    String result = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
    
  2. Using CharStreams (Guava)

    String result = CharStreams.toString(new InputStreamReader(
          inputStream, Charsets.UTF_8));
    
  3. Using Scanner (JDK)

    Scanner s = new Scanner(inputStream).useDelimiter("\\A");
    String result = s.hasNext() ? s.next() : "";
    
  4. Using Stream API (Java 8). Warning: This solution converts different line breaks (like \r\n) to \n.

    String result = new BufferedReader(new InputStreamReader(inputStream))
      .lines().collect(Collectors.joining("\n"));
    
  5. Using parallel Stream API (Java 8). Warning: This solution converts different line breaks (like \r\n) to \n.

    String result = new BufferedReader(new InputStreamReader(inputStream)).lines()
       .parallel().collect(Collectors.joining("\n"));
    
  6. Using InputStreamReader and StringBuilder (JDK)

    final int bufferSize = 1024;
    final char[] buffer = new char[bufferSize];
    final StringBuilder out = new StringBuilder();
    Reader in = new InputStreamReader(stream, StandardCharsets.UTF_8);
    int charsRead;
    while((charsRead = in.read(buffer, 0, buffer.length)) > 0) {
        out.append(buffer, 0, charsRead);
    }
    return out.toString();
    
  7. Using StringWriter and IOUtils.copy (Apache Commons)

    StringWriter writer = new StringWriter();
    IOUtils.copy(inputStream, writer, "UTF-8");
    return writer.toString();
    
  8. Using ByteArrayOutputStream and 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");
    
  9. Using BufferedReader (JDK). Warning: This solution converts different line breaks (like \n\r) to line.separator system property (for example, in Windows to "\r\n").

    String newLine = System.getProperty("line.separator");
    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
    StringBuilder result = new StringBuilder();
    boolean flag = false;
    for (String line; (line = reader.readLine()) != null; ) {
        result.append(flag? newLine: "").append(line);
        flag = true;
    }
    return result.toString();
    
  10. Using BufferedInputStream and ByteArrayOutputStream (JDK)

    BufferedInputStream bis = new BufferedInputStream(inputStream);
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
    int result = bis.read();
    while(result != -1) {
        buf.write((byte) result);
        result = bis.read();
    }
    // StandardCharsets.UTF_8.name() > JDK 7
    return buf.toString("UTF-8");
    
  11. Using inputStream.read() and StringBuilder (JDK). Warning: This solution has problems with Unicode, for example with Russian text (works correctly only with non-Unicode text)

    int ch;
    StringBuilder sb = new StringBuilder();
    while((ch = inputStream.read()) != -1)
        sb.append((char)ch);
    reset();
    return sb.toString();
    

Warning:

  1. Solutions 4, 5 and 9 convert different line breaks to one.

  2. Solution 11 can't work correctly with Unicode text

Performance tests

Performance tests for small String (length = 175), url in github (mode = Average Time, system = Linux, score 1,343 is the best):

              Benchmark                         Mode  Cnt   Score   Error  Units
 8. ByteArrayOutputStream and read (JDK)        avgt   10   1,343 ± 0,028  us/op
 6. InputStreamReader and StringBuilder (JDK)   avgt   10   6,980 ± 0,404  us/op
10. BufferedInputStream, ByteArrayOutputStream  avgt   10   7,437 ± 0,735  us/op
11. InputStream.read() and StringBuilder (JDK)  avgt   10   8,977 ± 0,328  us/op
 7. StringWriter and IOUtils.copy (Apache)      avgt   10  10,613 ± 0,599  us/op
 1. IOUtils.toString (Apache Utils)             avgt   10  10,605 ± 0,527  us/op
 3. Scanner (JDK)                               avgt   10  12,083 ± 0,293  us/op
 2. CharStreams (guava)                         avgt   10  12,999 ± 0,514  us/op
 4. Stream Api (Java 8)                         avgt   10  15,811 ± 0,605  us/op
 9. BufferedReader (JDK)                        avgt   10  16,038 ± 0,711  us/op
 5. parallel Stream Api (Java 8)                avgt   10  21,544 ± 0,583  us/op

Performance tests for big String (length = 50100), url in github (mode = Average Time, system = Linux, score 200,715 is the best):

               Benchmark                        Mode  Cnt   Score        Error  Units
 8. ByteArrayOutputStream and read (JDK)        avgt   10   200,715 ±   18,103  us/op
 1. IOUtils.toString (Apache Utils)             avgt   10   300,019 ±    8,751  us/op
 6. InputStreamReader and StringBuilder (JDK)   avgt   10   347,616 ±  130,348  us/op
 7. StringWriter and IOUtils.copy (Apache)      avgt   10   352,791 ±  105,337  us/op
 2. CharStreams (guava)                         avgt   10   420,137 ±   59,877  us/op
 9. BufferedReader (JDK)                        avgt   10   632,028 ±   17,002  us/op
 5. parallel Stream Api (Java 8)                avgt   10   662,999 ±   46,199  us/op
 4. Stream Api (Java 8)                         avgt   10   701,269 ±   82,296  us/op
10. BufferedInputStream, ByteArrayOutputStream  avgt   10   740,837 ±    5,613  us/op
 3. Scanner (JDK)                               avgt   10   751,417 ±   62,026  us/op
11. InputStream.read() and StringBuilder (JDK)  avgt   10  2919,350 ± 1101,942  us/op

Graphs (performance tests depending on Input Stream length in Windows 7 system)
enter image description here

Performance test (Average Time) depending on Input Stream length in Windows 7 system:

 length  182    546     1092    3276    9828    29484   58968

 test8  0.38    0.938   1.868   4.448   13.412  36.459  72.708
 test4  2.362   3.609   5.573   12.769  40.74   81.415  159.864
 test5  3.881   5.075   6.904   14.123  50.258  129.937 166.162
 test9  2.237   3.493   5.422   11.977  45.98   89.336  177.39
 test6  1.261   2.12    4.38    10.698  31.821  86.106  186.636
 test7  1.601   2.391   3.646   8.367   38.196  110.221 211.016
 test1  1.529   2.381   3.527   8.411   40.551  105.16  212.573
 test3  3.035   3.934   8.606   20.858  61.571  118.744 235.428
 test2  3.136   6.238   10.508  33.48   43.532  118.044 239.481
 test10 1.593   4.736   7.527   20.557  59.856  162.907 323.147
 test11 3.913   11.506  23.26   68.644  207.591 600.444 1211.545

@Steve Chambers 2020-08-01 11:16:23

Nice work. Could be useful to provide a tl;dr summary at the bottom, i.e. throwing out the solutions that have problems with line breaks / unicode and then (out of those that remain) saying which is fastest with or without external libraries.

@Paula Livingstone 2020-08-19 20:37:16

What is the reset(); for in 11?

@Gigino 2020-08-26 06:59:37

It seems this answer is incomplete

@user12402945 2019-11-20 12:49:24

This Code is for New Java Learners:

     private String textDataFromFile;

public String getFromFile(InputStream myInputStream) throws FileNotFoundException, IOException {

      BufferedReader bufferReader = new BufferedReader (new InputStreamReader(myInputStream));

       StringBuilder stringBuilder = new StringBuilder();

  String eachStringLine;

    while((eachStringLine=bufferReader.readLine()) != null){          
        stringBuilder.append(eachStringLine).append("\n");
    }

   textDataFromFile = stringBuilder.toString(); 



  return textDataFromFile;

}

@Tagir Valeev 2015-09-02 11:50:45

For completeness here is Java 9 solution:

public static String toString(InputStream input) throws IOException {
    return new String(input.readAllBytes(), StandardCharsets.UTF_8);
}

The readAllBytes is currently in JDK 9 main codebase, so it likely to appear in the release. You can try it right now using the JDK 9 snapshot builds.

@13hola 2018-06-28 12:45:51

I have created this code, and it works. There are no required external plug-ins.

There is a converter String to Stream and Stream to String:

import java.io.ByteArrayInputStream;
import java.io.InputStream;

public class STRINGTOSTREAM {

    public static void main(String[] args)
    {
        String text = "Hello Bhola..!\nMy Name Is Kishan ";

        InputStream strm = new ByteArrayInputStream(text.getBytes());    // Convert String to Stream

        String data = streamTostring(strm);

        System.out.println(data);
    }

    static String streamTostring(InputStream stream)
    {
        String data = "";

        try
        {
            StringBuilder stringbuld = new StringBuilder();
            int i;
            while ((i=stream.read())!=-1)
            {
                stringbuld.append((char)i);
            }
            data = stringbuld.toString();
        }
        catch(Exception e)
        {
            data = "No data Streamed.";
        }
        return data;
    }

@TacB0sS 2012-05-08 20:24:11

This is the best pure Java solution that fits perfectly for Android and any other JVM.

This solution works amazingly well... it is simple, fast, and works on small and large streams just the same!! (see benchmark above.. No. 8)

public String readFullyAsString(InputStream inputStream, String encoding)
        throws IOException {
    return readFully(inputStream).toString(encoding);
}

public byte[] readFullyAsBytes(InputStream inputStream)
        throws IOException {
    return readFully(inputStream).toByteArray();
}

private ByteArrayOutputStream readFully(InputStream inputStream)
        throws 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 baos;
}

@Daniel De León 2014-06-08 07:46:30

This one is nice because:

  • It safely handles the Charset.
  • You control the read buffer size.
  • You can provision the length of the builder and it doesn't have to be an exact value.
  • Is free from library dependencies.
  • Is for Java 7 or higher.

How to do it?

public static String convertStreamToString(InputStream is) throws IOException {
   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));
   }
   return sb.toString();
}

For JDK 9

public static String inputStreamString(InputStream inputStream) throws IOException {
    try (inputStream) {
        return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
    }
}

@Hasee Amarathunga 2019-03-28 08:49:36

I suggest the StringWriter class for that problem.

StringWriter wt= new StringWriter();
IOUtils.copy(inputStream, wt, encoding);
String st= wt.toString();

@toolforger 2020-01-22 08:29:46

IOUtils has a simpler function for that.

@HyperNeutrino 2015-11-17 03:23:02

Note: This probably isn't a good idea. This method uses recursion and thus will hit a StackOverflowError very quickly:

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

Please don't downvote this just because it's a bad choice to use; this was mostly creative :)

@Stephen C 2019-01-16 13:33:39

It is not just a bad choice. It will fail with a StackOverflowError if the input stream contains more than a few hundred characters.

@HyperNeutrino 2019-01-16 16:30:32

@StephenC That constitutes a bad choice in my opinion

@Stephen C 2019-01-16 22:20:42

I agree. It is a "bad choice" to use a method that doesn't work (except in trivial cases). But not just a "bad choice". Anyhow, I am down voting because this is wrong ... not because it is a "bad choice". And also because you don't explain why this approach should not be used.

@HyperNeutrino 2019-01-17 15:47:00

@StephenC I don't fundamentally agree with you, but thank you for at least leaving a comment instead of just fly-by downvoting. Recursion overflow issues are system limitations, and this method is not wrong, it just causes memory issues faster (albeit MUCH faster) than other methods.

@Stephen C 2019-01-17 22:30:52

For the Java language and implementations, the absence of tail-call optimization is a deliberate design choice; see softwareengineering.stackexchange.com/questions/272061/…. It should be viewed as inherent to Java. Certainly it is common to all extant mainstream Java implementations ... including Android.

@parsecer 2019-05-13 23:28:29

I liked your method, it's highly unusual. However, I don't get why it would "cause memory issues much faster"?

@HyperNeutrino 2019-05-14 18:20:27

@parsecer because instead of running out when the RAM can't handle the memory being used, it dies when the stack can't handle more stack calls, which is a lot smaller of a number on any reasonable system.

@Ilya Gazman 2018-02-13 21:30:08

I did a benchmark upon 14 distinct answers here (sorry for not providing credits but there are too many duplicates).

The result is very surprising. It turns out that Apache IOUtils is the slowest and ByteArrayOutputStream is the fastest solutions:

So first here is the best method:

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

Benchmark results, of 20 MB random bytes in 20 cycles

Time in milliseconds

  • ByteArrayOutputStreamTest: 194
  • NioStream: 198
  • Java9ISTransferTo: 201
  • Java9ISReadAllBytes: 205
  • BufferedInputStreamVsByteArrayOutputStream: 314
  • ApacheStringWriter2: 574
  • GuavaCharStreams: 589
  • ScannerReaderNoNextTest: 614
  • ScannerReader: 633
  • ApacheStringWriter: 1544
  • StreamApi: Error
  • ParallelStreamApi: Error
  • BufferReaderTest: Error
  • InputStreamAndStringBuilder: Error

Benchmark source code

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

}

@Dalibor 2019-05-16 22:08:04

Making benchmarks in Java is not easy (especially because of JIT). After reading Benchmark source code, I'm convinced that those values above are not precise and everyone should be careful by believing them.

@Ilya Gazman 2019-05-28 14:06:28

@Dalibor you probably should provide more reasoning for your claim rather than just a link.

@Dalibor 2019-05-29 22:04:46

I think that it is really known fact that it is not easy to make your own benchmark. For those who do not know that, there is link ;)

@Ilya Gazman 2019-05-29 23:56:47

@Dalibor I am perhaps not the best, but I have a good understanding of Java benchmarks, so unless you can point out a specific problem, you are just misleading, and I will not continue the conversation with you under those conditions.

@DavidS 2019-11-15 18:48:01

Mostly I agree with Dalibor. You say you have a "good understanding of Java benchmarks", but you seem to have implemented the most naive approach while being apparently ignorant of the well known issues of this approach. For starters, read every post on this question: stackoverflow.com/questions/504103/…

@Ilya Gazman 2019-11-15 20:59:38

@DavidS my test complies with the rules in the excepted answer that you linked. Are you able to point out for any problem in my implementation?

@DavidS 2019-11-15 21:55:56

From the accepted answer: Rule 0: Read the paper, which essentially warns against attempting a micro-benchmark. Rule 1: You have no warm up phase. Rule 2-3: You've given no indication you used these flags. Rule 8: Use a library like JMH. With 135 votes in the comments: Don't use System.currentTimeMillis(). Moving on to other highly voted answers. Jon Skeet: use System.gc() between iterations, and run your test long enough to measure the results in seconds, not milliseconds. Mixing tests in a single JVM run is bad, as the compiler optimizations done for one test will impact another.

@DavidS 2019-11-19 21:26:36

I have some free time, so here are a few more. Rule 5: You include the first iteration in your timing phase. Rule 6: You have used no special tools to "read the compilers mind". Rule 7: You have given no indication that you used these flags. There, I think that about covers it. I think that's every rule except for rule 4.

@Ilya Gazman 2019-11-20 03:36:34

@DavidS Rule 0,8: As I already mentioned, I know what I am doing, so this one does not applies here, there is more than one way to do things. Rule 1: of course I do, read my code more carefully, the test is called before the timer starts to worm up! As for System.gc(), it's just hint for for the system, you cannot trust it to do anything.

@Ilya Gazman 2019-11-20 03:38:28

@DavidS if you disagree with my implementation, run your own banchmark using what ever library you want and bring your results here. I be happy to compare

@DavidS 2019-11-20 18:02:26

You asked me to point out the problems. I have done so. I'm almost done trying to convince you, but here we go one more time. Rule 1: A single iteration is not a "warm up": the JIT compiler optimizes after thousands of iterations, not one. System.gc is a just a hint, but it's a very reliable one, and it would improve your tests. Finally, you are ignoring all of the other points: compiler flags, currentTimeMillis, splitting tests across multiple JVM runs. These are the serious problems with your attempt at benchmarking. I did not make them up myself: they are well known practices and tools.

@Ilya Gazman 2019-11-20 21:16:53

@DavidS I think you are miss reading this. Check out the input size. It's 1M byte array. Iterating on it once means the underline stream implementation is going todo a lot of loops.

@DavidS 2019-11-20 21:32:40

How many loops for warm-up? Will the loop count vary by algorithm used? Will it be enough to ensure the JIT compiler has achieved optimization? How would you know when it is enough? Wouldn't it be better to explicitly declare a warm-up phase with a known-number of iterations instead of relying on the underlying stream implementation? Wouldn't it be better to use a tool like JMH instead of trying to account for all of this?

@Ravi 2016-05-26 05:07:49

Also you can get InputStream from a specified resource path:

public static InputStream getResourceAsStream(String path)
{
    InputStream myiInputStream = ClassName.class.getResourceAsStream(path);
    if (null == myiInputStream)
    {
        mylogger.info("Can't find path = ", path);
    }

    return myiInputStream;
}

To get InputStream from a specific path:

public static URL getResource(String path)
{
    URL myURL = ClassName.class.getResource(path);
    if (null == myURL)
    {
        mylogger.info("Can't find resource path = ", path);
    }
    return myURL;
}

@Stephen C 2019-01-16 13:27:15

This does not answer the Question.

@Rys 2014-01-16 14:03:45

You can use Apache Commons.

In the IOUtils you can find the toString method with three helpful implementations.

public static String toString(InputStream input) throws IOException {
        return toString(input, Charset.defaultCharset());
}

public static String toString(InputStream input) throws IOException {
        return toString(input, Charset.defaultCharset());
}

public static String toString(InputStream input, String encoding)
            throws IOException {
        return toString(input, Charsets.toCharset(encoding));
}

@rkosegi 2018-10-03 19:13:57

What is difference between first 2 methods?

@Victor 2013-03-09 20:13:49

Well, you can program it for yourself... It's not complicated...

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

@user246645 2013-11-08 10:27:29

Since you're using buffer variable locally with no chance of being shared across multiple threads you should consider changing its type to StringBuilder, to avoid the overhead of (useless) synchronization.

@Victor 2013-11-08 16:19:44

That's a good point alex!. I thing that we both agree that this method isn't thread-safe in many ways. Even the input stream operations aren't thread-safe.

@Vlad Lifliand 2014-08-08 22:47:45

If the stream contains UTF-8 character that spans across several lines, this algorithm can cut the character in two breaking the string.

@Christian Hujer 2016-01-31 22:05:01

@VladLifliand How exactly would a UTF-8 character manage to span across several lines? That's impossible by definition. You probably meant something else.

@ᴠɪɴᴄᴇɴᴛ 2019-03-17 20:07:31

@ChristianHujer He probably means buffers instead of lines. UTF-8 codepoints/characters can be multi-byte.

@Christian Hujer 2019-03-19 08:07:43

Oh yes, they can, and most of them are, multi-byte in UTF-8. Only US-ASCII-7 is not multi-byte in UTF-8. If it's buffers, as in the code, it makes sense. Just not with lines.

@sampathpremarathna 2011-08-04 08:29:44

Use:

InputStream in = /* Your InputStream */;
StringBuilder sb = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String read;

while ((read=br.readLine()) != null) {
    //System.out.println(read);
    sb.append(read);
}

br.close();
return sb.toString();

@Pavel Repin 2011-03-26 20:40:25

Here's a way using only the standard Java library (note that the stream is not closed, your mileage may vary).

static String convertStreamToString(java.io.InputStream is) {
    java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
    return s.hasNext() ? s.next() : "";
}

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 constructor that indicates what character set to use (e.g. "UTF-8").

Hat tip goes also to Jacob, who once pointed me to the said article.

@DJDaveMark 2010-05-18 12:57:53

If you can't use Commons IO (FileUtils/IOUtils/CopyUtils), here's an example using a BufferedReader to read the file line by line:

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

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

@Jon Moore 2009-06-10 21:07:11

Use:

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

@Chinnery 2008-12-08 20:13:42

Apache Commons allows:

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

Of course, you could choose other character encodings besides UTF-8.

Also see: (documentation)

@Hans Brende 2018-11-07 23:21:37

ISO-8859-1

Here is a very performant way to do this if you know your input stream's encoding is ISO-8859-1 or ASCII. It (1) avoids the unnecessary synchronization present in StringWriter's internal StringBuffer, (2) avoids the overhead of InputStreamReader, and (3) minimizes the number of times StringBuilder's internal char array must be copied.

public static String iso_8859_1(InputStream is) throws IOException {
    StringBuilder chars = new StringBuilder(Math.max(is.available(), 4096));
    byte[] buffer = new byte[4096];
    int n;
    while ((n = is.read(buffer)) != -1) {
        for (int i = 0; i < n; i++) {
            chars.append((char)(buffer[i] & 0xFF));
        }
    }
    return chars.toString();
}

UTF-8

The same general strategy may be used for a stream encoded with UTF-8:

public static String utf8(InputStream is) throws IOException {
    StringBuilder chars = new StringBuilder(Math.max(is.available(), 4096));
    byte[] buffer = new byte[4096];
    int n;
    int state = 0;
    while ((n = is.read(buffer)) != -1) {
        for (int i = 0; i < n; i++) {
            if ((state = nextStateUtf8(state, buffer[i])) >= 0) {
                chars.appendCodePoint(state);
            } else if (state == -1) { //error
                state = 0;
                chars.append('\uFFFD'); //replacement char
            }
        }
    }
    return chars.toString();
}

where the nextStateUtf8() function is defined as follows:

/**
 * Returns the next UTF-8 state given the next byte of input and the current state.
 * If the input byte is the last byte in a valid UTF-8 byte sequence,
 * the returned state will be the corresponding unicode character (in the range of 0 through 0x10FFFF).
 * Otherwise, a negative integer is returned. A state of -1 is returned whenever an
 * invalid UTF-8 byte sequence is detected.
 */
static int nextStateUtf8(int currentState, byte nextByte) {
    switch (currentState & 0xF0000000) {
        case 0:
            if ((nextByte & 0x80) == 0) { //0 trailing bytes (ASCII)
                return nextByte;
            } else if ((nextByte & 0xE0) == 0xC0) { //1 trailing byte
                if (nextByte == (byte) 0xC0 || nextByte == (byte) 0xC1) { //0xCO & 0xC1 are overlong
                    return -1;
                } else {
                    return nextByte & 0xC000001F;
                }
            } else if ((nextByte & 0xF0) == 0xE0) { //2 trailing bytes
                if (nextByte == (byte) 0xE0) { //possibly overlong
                    return nextByte & 0xA000000F;
                } else if (nextByte == (byte) 0xED) { //possibly surrogate
                    return nextByte & 0xB000000F;
                } else {
                    return nextByte & 0x9000000F;
                }
            } else if ((nextByte & 0xFC) == 0xF0) { //3 trailing bytes
                if (nextByte == (byte) 0xF0) { //possibly overlong
                    return nextByte & 0x80000007;
                } else {
                    return nextByte & 0xE0000007;
                }
            } else if (nextByte == (byte) 0xF4) { //3 trailing bytes, possibly undefined
                return nextByte & 0xD0000007;
            } else {
                return -1;
            }
        case 0xE0000000: //3rd-to-last continuation byte
            return (nextByte & 0xC0) == 0x80 ? currentState << 6 | nextByte & 0x9000003F : -1;
        case 0x80000000: //3rd-to-last continuation byte, check overlong
            return (nextByte & 0xE0) == 0xA0 || (nextByte & 0xF0) == 0x90 ? currentState << 6 | nextByte & 0x9000003F : -1;
        case 0xD0000000: //3rd-to-last continuation byte, check undefined
            return (nextByte & 0xF0) == 0x80 ? currentState << 6 | nextByte & 0x9000003F : -1;
        case 0x90000000: //2nd-to-last continuation byte
            return (nextByte & 0xC0) == 0x80 ? currentState << 6 | nextByte & 0xC000003F : -1;
        case 0xA0000000: //2nd-to-last continuation byte, check overlong
            return (nextByte & 0xE0) == 0xA0 ? currentState << 6 | nextByte & 0xC000003F : -1;
        case 0xB0000000: //2nd-to-last continuation byte, check surrogate
            return (nextByte & 0xE0) == 0x80 ? currentState << 6 | nextByte & 0xC000003F : -1;
        case 0xC0000000: //last continuation byte
            return (nextByte & 0xC0) == 0x80 ? currentState << 6 | nextByte & 0x3F : -1;
        default:
            return -1;
    }
}

Auto-Detect Encoding

If your input stream was encoded using either ASCII or ISO-8859-1 or UTF-8, but you're not sure which, we can use a similar method to the last, but with an additional encoding-detection component to auto-detect the encoding before returning the string.

public static String autoDetect(InputStream is) throws IOException {
    StringBuilder chars = new StringBuilder(Math.max(is.available(), 4096));
    byte[] buffer = new byte[4096];
    int n;
    int state = 0;
    boolean ascii = true;
    while ((n = is.read(buffer)) != -1) {
        for (int i = 0; i < n; i++) {
            if ((state = nextStateUtf8(state, buffer[i])) > 0x7F)
                ascii = false;
            chars.append((char)(buffer[i] & 0xFF));
        }
    }

    if (ascii || state < 0) { //probably not UTF-8
        return chars.toString();
    }
    //probably UTF-8
    int pos = 0;
    char[] charBuf = new char[2];
    for (int i = 0, len = chars.length(); i < len; i++) {
        if ((state = nextStateUtf8(state, (byte)chars.charAt(i))) >= 0) {
            boolean hi = Character.toChars(state, charBuf, 0) == 2;
            chars.setCharAt(pos++, charBuf[0]);
            if (hi) {
                chars.setCharAt(pos++, charBuf[1]);
            }
        }
    }
    return chars.substring(0, pos);
}

If your input stream has an encoding that is neither ISO-8859-1 nor ASCII nor UTF-8, then I defer to the other answers already present.

@libnull-dev 2016-01-21 14:28:38

In terms of reduce, and concat it can be expressed in Java 8 as:

String fromFile = new BufferedReader(new   
InputStreamReader(inputStream)).lines().reduce(String::concat).get();

@Snekse 2017-01-26 19:40:23

In Groovy

inputStream.getText()

@Harry Lime 2008-11-21 16:54:20

A nice way to do this is using Apache commons IOUtils to copy the InputStream into a StringWriter... something like

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

or even

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

Alternatively, you could use ByteArrayOutputStream if you don't want to mix your Streams and Writers

@RCB 2020-07-02 15:26:20

Did the toString get deprecated? I see IOUtils.convertStreamToString()

@drakeet 2018-04-07 12:53:23

With Okio:

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

@Steve Chambers 2015-12-24 11:08:53

Based on the second part of the accepted Apache Commons answer but with the small gap filled in for always closing the stream:

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

@Ilya Gazman 2018-04-05 14:57:02

Note that this solution is the most inefficient based on my benchmark results

@jmehrens 2016-01-28 15:55:21

Use the java.io.InputStream.transferTo(OutputStream) supported in Java 9 and the ByteArrayOutputStream.toString(String) which takes the charset name:

public static String gobble(InputStream in, String charsetName) throws IOException {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    in.transferTo(bos);
    return bos.toString(charsetName);
}

@gil.fernandes 2017-10-21 09:46:13

This solution to this question is not the simplest, but since NIO streams and channels have not been mentioned, here goes a version which uses NIO channels and a ByteBuffer to convert a stream into a string.

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

Here is an example how to use it:

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

The performance of this method should be good for large files.

@Brett Holt 2011-10-12 17:23:01

I ran some timing tests because time matters, always.

I 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();
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 for grabbing a response and creating a String from it.

@yegor256 2017-08-06 18:08:30

You can use Cactoos:

String text = new TextOf(inputStream).asString();

UTF-8 encoding is the default one. If you need another one:

String text = new TextOf(inputStream, "UTF-16").asString();

@James 2016-07-29 20:58:25

Another one, for all the Spring users:

import java.nio.charset.StandardCharsets;
import org.springframework.util.FileCopyUtils;

public String convertStreamToString(InputStream is) throws IOException { 
    return new String(FileCopyUtils.copyToByteArray(is), StandardCharsets.UTF_8);
}

The utility methods in org.springframework.util.StreamUtils are similar to the ones in FileCopyUtils, but they leave the stream open when done.

@Halfacht 2017-05-10 11:38:07

Raghu K Nair Was the only one using a scanner. The code I use is a little different:

String convertToString(InputStream in){
    Scanner scanner = new Scanner(in)
    scanner.useDelimiter("\\A");

    boolean hasInput = scanner.hasNext();
    if (hasInput) {
        return scanner.next();
    } else {
        return null;
    }

}

About Delimiters: How do I use a delimiter in Java Scanner?

Related Questions

Sponsored Content

95 Answered Questions

[SOLVED] How do I make the first letter of a string uppercase in JavaScript?

81 Answered Questions

[SOLVED] Is Java "pass-by-reference" or "pass-by-value"?

46 Answered Questions

[SOLVED] How do I convert a String to an int in Java?

70 Answered Questions

[SOLVED] How to replace all occurrences of a string?

19 Answered Questions

[SOLVED] Convert bytes to a string

10 Answered Questions

[SOLVED] Does Python have a string 'contains' substring method?

63 Answered Questions

[SOLVED] What is the difference between String and string in C#?

3 Answered Questions

17 Answered Questions

[SOLVED] Why is char[] preferred over String for passwords?

Sponsored Content