Stream Classes in Java’s IO Package: An Essential Guide

Stream classes in the java.io package are an essential part of performing input and output operations in Java. They allow us to read and write data to various sources such as files, network sockets, and in-memory buffers.

There are two types of streams in Java: input streams and output streams. Input streams are used to read data from a source and are subclasses of the InputStream class. Output streams are used to write data to a destination and are subclasses of the OutputStream class.

Following are some examples of stream classes and their uses:

FileInputStream

The FileInputStream class is a subclass of InputStream and allows reading bytes from a file. It is used to read data from a file or a part of a file. To use a FileInputStream, we must first create an instance of the class by specifying the file or file descriptor that we want to read from. Then, we can call the read() method to read bytes from the file. We can also use the skip() method to skip a specific number of bytes, or the available() method to determine the number of bytes that can be read from the stream.

Here is an example of how to use a FileInputStream to read the contents of a file:

import java.io.*;

public class Main {
  public static void main(String[] args) throws IOException {
    FileInputStream fis = new FileInputStream("file.txt");
    int b;
    while((b = fis.read()) != -1) {
      System.out.print((char)b);
    }
    fis.close();
  }
}

This code will open the file “file.txt”. It reads the contents one byte at a time, until it reaches the end of the file. The bytes are then cast to characters and printed to the console. Finally, the close() method is called to close the stream and release any system resources associated with it.

FileOutputStream

The FileOutputStream class is a subclass of OutputStream and allows writing bytes to a file. It is used to write data to a file or to a file descriptor. To use a FileOutputStream, we must first create an instance of the class by specifying the file or file descriptor that we want to write to. We can then call the write() method to write bytes to the file. If the file does not exist, it will be created. If it does exist, the data will be overwritten.

Here is an example of how to use a FileOutputStream to write to a file:

import java.io.*;

public class Main {
  public static void main(String[] args) throws IOException {
    FileOutputStream fos = new FileOutputStream("file.txt");
    String s = "Hello, world!";
    fos.write(s.getBytes());
    fos.close();
  }
}

This code will create a new file called “file.txt” (or overwrite the file if it already exists). And write the string “Hello, world!” to it. The string is first converted to an array of bytes using the getBytes() method, and then written to the file using the write() method. Finally, the close() method is called to close the stream and release any system resources associated with it.

It is important to note that the FileOutputStream does not automatically flush the data to the file. We must call the flush() method to ensure that the data is written to the file. We should also close the stream when We are done writing to it to ensure that all the data is properly written and release any system resources.

BufferedInputStream

The BufferedInputStream class is a subclass of FilterInputStream and is used to read data from an input stream in a buffered manner. A buffer is a block of data that is stored temporarily in memory. And is used to reduce the number of read and write operations on the underlying input or output stream.

Using a BufferedInputStream can improve the performance of our program, because it reduces the number of calls to the underlying input stream and reduces the overhead of reading from the stream. It does this by reading larger blocks of data from the input stream and storing them in a buffer, and then serving the data from the buffer to the application as needed.

To use a BufferedInputStream, we must first create an instance of the class by specifying the input stream that we want to read from and the size of the buffer. We can then call the read() method to read bytes from the stream.

Here is an example of how to use a BufferedInputStream to read from a file:

import java.io.*;

public class Main {
  public static void main(String[] args) throws IOException {
    FileInputStream fis = new FileInputStream("file.txt");
    BufferedInputStream bis = new BufferedInputStream(fis, 1024);
    int b;
    while((b = bis.read()) != -1) {
      System.out.print((char)b);
    }
    bis.close();
  }
}

This code will create a BufferedInputStream with a buffer size of 1024 bytes and read from the file “file.txt” using the read() method. The bytes are then cast to characters and printed to the console. Finally, the close() method is called to close the stream and release any system resources associated with it.

BufferedOutputStream

The BufferedOutputStream class is a subclass of FilterOutputStream and is used to write data to an output stream in a buffered manner.

Using a BufferedOutputStream can also improve the performance of our program same as BufferedInputStream.

To use a BufferedOutputStream, we must first create an instance of the class by specifying the output stream that we want to write to and the size of the buffer. We can then call the write() method to write bytes to the stream.

Here is an example of how to use a BufferedOutputStream to write to a file:

import java.io.*;

public class Main {
  public static void main(String[] args) throws IOException {
    FileOutputStream fos = new FileOutputStream("file.txt");
    BufferedOutputStream bos = new BufferedOutputStream(fos, 1024);
    String s = "Hello, world!";
    bos.write(s.getBytes());
    bos.flush();
    bos.close();
  }
}

This code will create a BufferedOutputStream with a buffer size of 1024 bytes and write the string “Hello, world!” to the file “file.txt”. The string is first converted to an array of bytes using the getBytes() method and then written to the file using the write() method. The flush() method is then called to ensure that all the data is written to the file. Finally, the close() method is called to close the stream and release any system resources associated with it.

DataInputStream

The DataInputStream class is a subclass of FilterInputStream and is used to read primitive data types from an input stream in a machine-independent manner. It provides methods for reading bytes, shorts, ints, longs, floats, and doubles, as well as strings and characters.

To use a DataInputStream, we must first create an instance of the class by specifying the input stream that we want to read from. We can then call the appropriate method to read the data type that we are interested in.

Here is an example of how to use a DataInputStream to read a file containing a list of integers:

import java.io.*;

public class Main {
  public static void main(String[] args) throws IOException {
    FileInputStream fis = new FileInputStream("file.dat");
    DataInputStream dis = new DataInputStream(fis);
    int i;
    while(dis.available() > 0) {
      i = dis.readInt();
      System.out.println(i);
    }
    dis.close();
  }
}

This code will create a DataInputStream and read from the file “file.dat” using the readInt() method. The integers are then printed to the console. The available() method is used to determine whether there is any more data to read. The close() method is called to close the stream and release any system resources associated with it.

It is important to note that the DataInputStream expects the data to be in the same format that it was written in. If the data was not written using a DataOutputStream, or if the data was written in a different order or with different data types, the DataInputStream may not be able to read it correctly.

DataOutputStream

The DataOutputStream class is a subclass of FilterOutputStream and is used to write primitive data types to an output stream in a machine-independent manner. It provides methods for writing bytes, shorts, ints, longs, floats, and doubles, as well as strings and characters.

To use a DataOutputStream, we must first create an instance of the class by specifying the output stream that we want to write to. We can then call the appropriate method to write the data type that we are interested in.

Here is an example of how to use a DataOutputStream to write a list of integers to a file:

import java.io.*;

public class Main {
  public static void main(String[] args) throws IOException {
    FileOutputStream fos = new FileOutputStream("file.dat");
    DataOutputStream dos = new DataOutputStream(fos);
    int[] data = {1, 2, 3, 4, 5};
    for(int i : data) {
      dos.writeInt(i);
    }
    dos.close();
  }
}

This code will create a DataOutputStream and write the array of integers to the file “file.dat” using the writeInt() method. The close() method is called to close the stream and release any system resources associated with it.

The DataOutputStream writes the data in a machine-independent format, so it can be read by a DataInputStream on any machine, regardless of the endianness or data representation of the machine. This is useful for storing data that needs to be transferred between different systems or platforms.

It’s important to note that stream classes in Java are byte-oriented. Which means they read and write data in the form of bytes. If we need to work with character data, we should use a Reader or Writer class instead.

Here are some additional methods that are available in the InputStream and OutputStream classes:

  • read(byte[] b): This method reads b.length number of bytes from the input stream and stores them in the provided byte array b.
  • write(byte[] b): This method writes b.length number of bytes from the provided byte array b to the output stream.
  • skip(long n): This method skips n number of bytes in the input stream.
  • available(): This method returns the number of bytes that can be read from the input stream without blocking.
  • reset(): This method resets the input stream to the last mark position.
  • mark(int readlimit): This method marks the current position in the input stream and allows us to reset the stream to this position later.
  • flush(): This method flushes the output stream, ensuring that any buffered data is written to the destination.

It’s important to use these stream classes responsibly by remembering to close them when we are finished with them. Failure to do so can result in resource leaks and other issues.

In summary, stream classes in the java.io package are a valuable tool for performing input and output operations in Java. They provide a way to read and write data to various sources and offer a variety of methods to improve the performance of our input and output operations.