Input Output Streams in Java

A stream is a flow of data or channel of communication. A stream is connected to a physical device by a Java I/O system that either produces or consumes data.

In Java, IO (Input/Output) streams provide a way to perform input and output operations with various data sources, such as files, network connections, and memory.

IO streams are classified into two categories:

  1. Byte Streams: Byte-oriented IO streams read or write data in the form of bytes. Byte streams are used for handling binary data, such as images, audio files, or any other file that doesn't consist of plain text.
  2. Character Streams: Character-oriented IO streams read or write data in the form of characters. Character streams are used for processing text-based data, such as reading or writing text files.

The byte stream classes and the character streams classes form separate hierarchies. In general, use the byte streams classes when working with bytes and binary objects and use the character stream classes when working with characters and strings.


Byte Stream Classes

Byte stream classes are used to handle input and output of raw bytes. They are primarily used for reading from and writing to binary files or network sockets. Java provides several built-in byte stream classes in the java.io package. Here are some commonly used byte stream classes:

  • InputStream: It is the abstract base class for all byte input streams. It defines the basic methods for reading bytes.
  • OutputStream: It is the abstract base class for all byte output streams. It defines the basic methods for writing bytes.
  • FileInputStream: This class is used for reading from files as byte streams. It is constructed with a file name or File object.
  • FileOutputStream: This class is used for writing to files as byte streams. It is constructed with a file name or File object.
  • ByteArrayInputStream: This class allows reading from an in-memory byte array. It can be useful for buffering or temporary storage of byte data.
  • ByteArrayOutputStream: This class allows writing to an in-memory byte array. It can be useful for buffering or temporary storage of byte data.
  • BufferedInputStream: This class provides buffering capabilities to improve the performance of byte input operations. It wraps another byte stream and reads data in larger chunks.
  • BufferedOutputStream: This class provides buffering capabilities to improve the performance of byte output operations. It wraps another byte stream and writes data in larger chunks.
  • DataInputStream: This class provides methods for reading primitive data types (e.g., int, double, boolean) as binary data. It wraps another byte stream and provides additional functionality for handling different data types.
  • DataOutputStream: This class provides methods for writing primitive data types (e.g., int, double, boolean) as binary data. It wraps another byte stream and provides additional functionality for handling different data types.
  • ObjectInputStream: This class allows reading Java objects as byte streams. It provides serialization capabilities, allowing objects to be converted into bytes.
  • ObjectOutputStream: This class allows writing Java objects as byte streams. It provides deserialization capabilities, allowing bytes to be converted into objects.
  • PipedInputStream and PipedOutputStream: These classes allow communication between two threads using a pipe. Data written to the output stream can be read from the input stream. PipedInputStream is typically used in conjunction with PipedOutputStream to establish a communication channel between a producer thread and a consumer thread.

These are just a few examples of byte stream classes in Java. They offer different functionalities and can be combined or used separately based on your specific requirements for handling byte-level data.


Character Stream Classes

Character stream classes are used to handle input and output of character data, providing a higher-level abstraction compared to byte streams. They are primarily used for reading from and writing to text files, or for processing text-based data. Java provides several built-in character stream classes in the java.io package. Here are some commonly used character stream classes:

  • Reader: This is the abstract base classes for all character input streams. It defines the basic methods for reading characters.
  • Writer: This is the abstract base classes for all character output streams. It defines the basic methods for writing characters.
  • FileReader: This class is used for reading from files as character streams. It is constructed with a file name or File object.
  • FileWriter: This class is used for writing to files as character streams. It is constructed with a file name or File object.
  •  CharArrayReader: This class allows reading from an in-memory character array. It can be useful in scenarios where you have character data stored in a char array and need to process or read it as a character stream.
  • CharArrayWriter: This class allows writing to an in-memory character array. It can be useful when you need to collect and manipulate character data before storing it in a file or passing it to another component.
  • BufferedReader: This class provides buffering capabilities to improve the performance of character input operations. It wraps another character stream and allows to read data in larger chunks.
  • BufferedWriter: This class provides buffering capabilities to improve the performance of character output operations. It allows to write data in larger chunks.
  • InputStreamReader: This class bridges the gap between byte streams and character streams. It converts bytes to characters using a specified character encoding. It is typically used when working with byte streams and need to handle character data.
  • OutputStreamWriter: This class bridges the gap between character streams and byte streams . It converts characters to bytes using a specified character encoding. It is typically used when working with character streams and need to handle byte data.
  • PrintWriter: This class provides convenient methods for writing formatted text to a character output stream. It can be used for writing text data to a file or any other character output stream.
  • StringReader and StringWriter: These classes allow you to read from and write to strings as if they were input/output streams. These classes are useful when you want to treat strings as data sources or destinations.

These are some examples of character stream classes in Java. They offer higher-level operations for handling character data, such as reading and writing text files or processing textual information. The choice of which class to use depends on the specific requirements of your application.


InputStream Example

Here's an example to read a file using InputStream in Java: 

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class Sample {

   public static void main(String[] args) {
		
      InputStream inputStream = null;
      try {
	   // Creating an input stream for reading a file
	   inputStream = new FileInputStream("example.txt");

	   // Read bytes from the input stream
	   int byteValue;
	   while ((byteValue = inputStream.read()) != -1) {
	      // Process the byte
	      char c = (char) byteValue;
	      System.out.print(c);
	   }

	} catch (IOException e) {
	   e.printStackTrace();
	} finally {

	   // Always make sure to close the input stream in the finally block
	   if (inputStream != null) {
	      try {
		  inputStream.close();
	      } catch (IOException e) {
	          e.printStackTrace();
	      }
	   }
	}
   }
}

In this example, we use FileInputStream to create an InputStream for reading a file named "example.txt". We then use the read() method of the InputStream to read bytes from the file one by one. The read() method returns an integer value representing the byte read, or -1 if the end of the stream has been reached.

We convert the byte value to a character using (char) byteValue and print it to the console. Finally, we close the input stream in the finally block to release any system resources associated with it.

Note that handling exceptions and closing the stream properly is important to ensure resource cleanup and prevent memory leaks.


OutputStream Example

Here's an example to write data to a file using OutputStream in Java: 

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class Example {

   public static void main(String[] args) {

      OutputStream outputStream = null;
      try {
	    // Creating a new output stream for writing to a file
	    outputStream = new FileOutputStream("example.txt");

	    String message = "Hello, example!";

	    // Convert string data to a byte array
	    byte[] data = message.getBytes();

	    // Writing the byte array to the output stream
	    outputStream.write(data);

	    System.out.println("Writing complete...");

       } catch (IOException e) {
          e.printStackTrace();
       } finally {
           try {
		  // Closing the output stream
		  if (outputStream != null) {
		      outputStream.close();
		  }

	    } catch (IOException e) {
	        e.printStackTrace();
	    }
       }
   }

}

In this example, we create an instance of FileOutputStream to write data to a file named "example.txt". We convert the string message into a byte array using the getBytes() method, and then write the byte array to the output stream using the write() method. Finally, we close the output stream in the finally block to ensure proper resource cleanup.



Reader Example

Here's an example that demonstrates how to read the contents of a text file using the Reader class from the java.io package:

import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class Example {

   public static void main(String[] args) {

      // Replace with your file path
      String filePath = "C:/Users/hello/Downloads/example.txt";

      try (Reader reader = new FileReader(filePath)) {
          int charValue;
          while ((charValue = reader.read()) != -1) {
             char character = (char) charValue;
	     System.out.print(character);
          }
       } catch (IOException e) {
          System.out.println("Error occurred while reading the file: " + e.getMessage());
       }
   }

}

In this example, the code defines a public class named Example. The main method serves as the entry point for the program. The variable filePath is a string that represents the path of the file to be read. In this example, the file path is set to "C:/Users/hello/Downloads/example.txt". You would need to replace this with the actual path to the file you want to read. The code is wrapped in a try-with-resources statement, which ensures that the Reader object is properly closed after it's used. The Reader object is created using the FileReader class and is initialized with the filePath. Within the try block, there is a loop that reads the contents of the file character by character. The read() method of the Reader class returns the next character in the file as an integer. The loop continues until the read() method returns -1, which indicates the end of the file. Inside the loop, the integer value returned by read() is cast to a char and stored in the variable character. Then, the character is printed using System.out.print(). If any exception occurs during the file reading process, an IOException will be thrown. The catch block catches the exception, and an error message is displayed using System.out.println().


Writer Example

Here's an example that demonstrates how to write data to a text file using Writer class from the java.io package:

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

public class Example {

   public static void main(String[] args) {

      // Replace with your file path
      String filePath = "C:/Users/hello/Downloads/example.txt";

      try (Writer writer = new FileWriter(filePath)) {
         String content = "Hello, World!";
	 writer.write(content);
	 System.out.println("Content written to the file successfully.");
      } catch (IOException e) {
         System.out.println("Error occurred while writing to the file: " + e.getMessage());
      }
   }

}

In this example, we use the Writer class to write content to a text file. The Example class is defined as a public class. The main method serves as the entry point for the program. The filePath variable represents the path to the file where you want to write the content. Make sure to replace it with the actual file path. Inside the try block, a Writer object is created using the FileWriter class and is initialized with the filePath. The write() method of the Writer class is used to write the content to the file. In this example, the content is set to "Hello, World!".Finally, a success message is printed to the console indicating that the content was written to the file successfully. If any exception occurs during the file writing process, an IOException will be thrown. The catch block catches the exception, and an error message is displayed.