Friday, July 21, 2023

3 Examples to Read FileInputStream as String in Java - JDK7, Guava and Apache Commons

Java programming language provides streams to read data from a file, a socket and from other sources e.g. byte array, but developers often find themselves puzzled with several issues e.g. how to open connection to read data, how to close connection after reading or writing into file, how to handle IOException e.g. FileNotFoundException, EOFFileException etc. They are not confident enough to say that this code will work perfectly.  Well, not everyone expect you to make that comment, but having some basics covered always helps. For example In Java, we read data from file or socket using InputStream and write data using OutputStream. Inside Java program, we often use String object to store and pass file data, that's why we need a way to convert InputStream to String in Java. As a Java developer, just keep two things in mind while reading InputStream data as String :

1) Don't forget to close InputStream, Readers and other resources, once you are done with them. Each InputStream keeps a file descriptor object, which is a limited resource in system. Similarly each socket also holds a file descriptor, by closing input stream and socket you release this limited resources. Failing to so may result in file descriptor error e.g. you may get too many open files error, while opening new files.

2) Always specify character encoding while reading text data from InputStream as String. When you create InputStreamReader, it has an overloaded constructor which accepts a character encoding e.g. we have provided StandardCharsets.UTF_8 in our example. You can also pass "UTF-8" as String, but prefer StandardCharsets.UTF_8 to avoid typing mistakes. 

In the absence of character encoding, IO classes from Java API uses default character encoding of platform they are running, which may not be same as contents of your file. For example, if your file contains UTF-8 characters, which is not supported by your platform encoding then they will be shown as either ???? or as little square bracket.

Now let's come to second part, how do you get InputStream data as String? Well there are many ways to do that in Java, you can either use Scanner, BufferedReader, or can use third-party libraries like Apache commons IO and Google Guava for simplifying this task. In this tutorial, we will see 3 different ways to read InputStream as String in Java.




Example 1 : Using Core Java classes

This is my preferred way of converting InputStream to String, as it doesn't require any third-party JAR. This approach is also best suited to applications running on Java 7, as we are using try-with-resource statements to automatically close input streams, but you can just take out that piece and can close streams in the finally block if you are running on Java 6 or lower version.

Here are the steps and  code sample of reading InputStream as String in Java :

Step 1: Open FileInputStream to read contents of File as InputStream.
Step 2: Create InputStreamReader with character encoding to read byte as characters
Step 3: Create BufferedReader to read file data line by line
Step 4: Use StringBuilder to combine lines

here is Java code for reading InputStream as String :
try (InputStream in = new FileInputStream("finance.txt"); 
     BufferedReader r = new BufferedReader(
               new InputStreamReader(in, StandardCharsets.UTF_8))) {     
      String str = null;
      StringBuilder sb = new StringBuilder(8192);
      while ((str = r.readLine()) != null) {
        sb.append(str);
      }
      System.out.println("data from InputStream as String : " + sb.toString());
} catch (IOException ioe) {
  ioe.printStackTrace();
}

Closing of InputStream is taken care by Java itself because they are declared as try-with-resource statement. Our File contains a single line, which contains some French characters, to demonstrate use of character encoding. We have provided UTF-8 to InputStreamReader just for this purpose. Since we are using StringBuilder, there is an opportunity to tune its size depending upon how large file is.


Example 2 : Using Apache Commons IO

In this example, we are using IOUtils class from Apache commons IO to read InputStream data as String. It provides a toString() method to convert InputStream to String. This is by far most easiest way to get String from stream, but you should also don't rely on them to close your streams. If you have opened stream, then it’s always better you close it. That's why I am using automatic resource management feature of Java 7, which closes any resource opened in try() statement.

try (FileInputStream fis = new FileInputStream("finance.txt");) {
     String text = IOUtils.toString(fis, StandardCharsets.UTF_8.name());
     System.out.println("String generated by reading InputStream in Java : "
                      + text);
} catch (IOException io) {
  io.printStackTrace();
}

Example 3 : Using Google Guava library

In this example, we have used Google Guava library to read contents of InputStream as String. Here input stream is not obtained from file instead from a byte array, which is generated by converting an String to byte array. It always better to provide encoding while calling getBytes() method of String, so that data is converted correctly. If you look at our example, we have provided "UTF-8", though you can also use StandardCharsets.UTF_8.name(). Remember CharStreams.toString() doesn't close Stream from which it is reading characters, that's why we have opened stream in try (...) parenthesis, so that it will be automatically closed by Java.
String stringWithSpecialChar = "Société Générale";
try (final InputStream in 
       = new ByteArrayInputStream(stringWithSpecialChar.getBytes("UTF-8"));
     final InputStreamReader inr = new InputStreamReader(in)) {
     String text = CharStreams.toString(inr);
     System.out.println("String from InputStream in Java: " + text);
} catch (IOException e) {
     e.printStackTrace();
}


Revision of Java Input Output Basics3 examples to read InputStream as String in Java


For quick revision of basic input output concept in Java, you can refer to above diagram. It explains concept of how to read and write date e.g. bytes from input source like file, network, keyboard and writing data to console, file, network and program. InputStream is used to read data and OutputStream is used to write data. Data can be on any format e.g. Text or Binary. 

You can even read data in particular type by using DataInputStream. Java provides char, int, float, double, long and other data types to store data read in that way. Character streams e.g. Readers are used to read character data while Byte Streams e.g. InputStream are used to read binary data.



Complete Java Program of InputStream to String in Java

Here is our full code listing of 3 ways to read InputStream as String in Java Program. In order to run this program, copy this code into a file and save it as InputStreamToString.java, after this compile this file using javac command, if javac is not in your included in your PATH environment variable, then you can directly run it from bin folder of your JDK installation directory, also known as JAVA_HOME

After compilation, you can run your program by using java command e.g. java -classpath . InputStreamToString . By the way, if you still struggle to run a Java program from command prompt then you can also see this step by step tutorial on how to run Java application from command line.

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.Charsets;
import org.apache.commons.io.IOUtils;
import com.google.common.io.CharStreams;
import com.google.common.io.InputSupplier;

/**
 * Java Program to demonstrate 3 ways of reading file data using InputStream
 * as String. Though second example, read it from a byte array.
 * It shows examples from core Java, Google Guava and Apache commons library.
 *
 * @author Javin Paul
 */
public class InputStreamToString {

    public static void main(String args[]) {

        // InputStream to String - Core Java Example
        try (InputStream in = new FileInputStream("finance.txt");
                BufferedReader r = new BufferedReader(
                   new InputStreamReader(in, StandardCharsets.UTF_8))) {
            String str = null;
            StringBuilder sb = new StringBuilder(8192);
            while ((str = r.readLine()) != null) {
                sb.append(str);
            }
            System.out.println("data from InputStream as String : " 
                               + sb.toString());
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }


        // Converting InputStream to String in Java - Google Guava Example
        String stringWithSpecialChar = "Société Générale";
        try (final InputStream in 
               = new ByteArrayInputStream(stringWithSpecialChar.getBytes("UTF-8"));
                final InputStreamReader inr = new InputStreamReader(in)) {
            String text = CharStreams.toString(inr);
            System.out.println("String from InputStream in Java: " + text);
        } catch (IOException e) {
            e.printStackTrace();
        }


        // Reading data from InputStream as String in Java
        // - Apache Commons Example
        try (FileInputStream fis = new FileInputStream("finance.txt");) {
            String text = IOUtils.toString(fis, StandardCharsets.UTF_8.name());
            System.out.println("String generated by reading InputStream in Java 
                                  : " + text);
        } catch (IOException io) {
            io.printStackTrace();
        }
    }
}
Output:
data from InputStream as String : Société Générale is 
a French bank Headquarters at Île-de-France, France
String from InputStream in Java: Société Générale
String generated by reading InputStream in Java : 
Société Générale is a French bank Headquarters at Île-de-France, France

That's all about How to read InputStream as String in Java. Streams are there for a reason, which usually allows you to process a file of arbitrary content using limited memory, keeping full content of the file as String can take a lot of memory, so you would like to check your approach if you are thinking to keep all contents as String. 

On the other hand, many times we need to process files line by line, and that time, we had to read String from InputStream, which is Ok. 

Just remember to provide correct character encoding while reading text data from InputStream as String, and always close streams which you have opened. If you are running on Java 7, use try-with-resources by default.

If you love to know more about String data structure in Java, check out these amazing articles from this blog

4 comments:

Feel free to comment, ask questions if you have any doubt.