Skip to content

Filtered Byte Streams in Java

Filtered Byte Streams in Java are specialized byte streams that provide additional functionalities by processing data from other streams. They act as wrappers for existing streams and are part of the Decorator Design Pattern in the Java I/O framework. These streams allow features like buffering, data manipulation, and specific format handling.

Filtered streams belong to the java.io package and are used to process binary data efficiently.


Core Characteristics of Filtered Byte Streams

  1. Wrapper Streams:
    1. Filtered streams do not directly connect to a data source (like a file).
    1. Instead, they wrap around other streams (e.g., FileInputStream) to add additional functionality.
  2. Primary Classes:
    1. FilteredInputStream: A superclass for all input stream filters.
    1. FilteredOutputStream: A superclass for all output stream filters.
  3. Enhancement:
    1. Enable functionalities like buffering, reading data in specific formats, and encryption.

Types of Filtered Byte Streams

StreamInput ClassOutput Class
Buffered StreamsBufferedInputStreamBufferedOutputStream
Data StreamsDataInputStreamDataOutputStream
Checked StreamsCheckedInputStreamCheckedOutputStream
Digest StreamsDigestInputStreamDigestOutputStream
Cipher Streams (Crypto)CipherInputStreamCipherOutputStream
Inflater/DeflaterInflaterInputStreamDeflaterOutputStream

Common Filtered Byte Streams

  1. Buffered Streams:
    1. Improve I/O performance by using an internal buffer.
    1. Classes: BufferedInputStream, BufferedOutputStream.
  2. Data Streams:
    1. Allow reading and writing of Java’s primitive data types (e.g., int, float, double).
    1. Classes: DataInputStream, DataOutputStream.
  3. Checked Streams:
    1. Used for stream integrity checks via checksum calculations.
    1. Classes: CheckedInputStream, CheckedOutputStream.
  4. Digest Streams:
    1. Provide cryptographic hash calculation for stream data.
    1. Classes: DigestInputStream, DigestOutputStream.
  5. Cipher Streams:
    1. Handle encryption and decryption of stream data.
    1. Classes: CipherInputStream, CipherOutputStream (in the javax.crypto package).
  6. Inflater/Deflater Streams:
    1. Handle compression and decompression of stream data.
    1. Classes: InflaterInputStream, DeflaterOutputStream.

Key Methods

Common Methods in FilteredInputStream

  • int read(): Reads a single byte from the input stream.
  • int read(byte[] b, int off, int len): Reads up to len bytes into the specified array.
  • void close(): Closes the stream and releases system resources.

Common Methods in FilteredOutputStream

  • void write(int b): Writes a single byte to the output stream.
  • void write(byte[] b, int off, int len): Writes len bytes from the specified array.
  • void close(): Closes the stream and releases system resources.

Examples

Example 1: Buffered Streams

import java.io.*;

public class BufferedStreamExample {

    public static void main(String[] args) {

        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(“input.txt”));

             BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(“output.txt”))) {

            int data;

            while ((data = bis.read()) != -1) {

                bos.write(data);

            }

            System.out.println(“File copied successfully using buffered streams.”);

        } catch (IOException e) {

            e.printStackTrace();

        }

    }

}


Example 2: Data Streams

import java.io.*;

public class DataStreamExample {

    public static void main(String[] args) {

        try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(“data.bin”));

             DataInputStream dis = new DataInputStream(new FileInputStream(“data.bin”))) {

            // Write primitive data types to the file

            dos.writeInt(42);

            dos.writeDouble(3.14);

            dos.writeBoolean(true);

            // Read the data back

            System.out.println(“Int: ” + dis.readInt());

            System.out.println(“Double: ” + dis.readDouble());

            System.out.println(“Boolean: ” + dis.readBoolean());

        } catch (IOException e) {

            e.printStackTrace();

        }

    }

}


Example 3: Checked Streams

import java.io.*;

import java.util.zip.*;

public class CheckedStreamExample {

    public static void main(String[] args) {

        try (CheckedOutputStream cos = new CheckedOutputStream(new FileOutputStream(“checkedData.bin”), new Adler32());

             CheckedInputStream cis = new CheckedInputStream(new FileInputStream(“checkedData.bin”), new Adler32())) {

            // Write data to the file

            cos.write(“Hello, Checksum!”.getBytes());

            // Get checksum

            System.out.println(“Written checksum: ” + cos.getChecksum().getValue());

            // Read the file and calculate checksum

            byte[] buffer = new byte[1024];

            while (cis.read(buffer) != -1) {}

            System.out.println(“Read checksum: ” + cis.getChecksum().getValue());

        } catch (IOException e) {

            e.printStackTrace();

        }

    }

}


Advantages of Filtered Byte Streams

  1. Enhanced Functionality:
    1. Add features like buffering, compression, encryption, and format-specific reading/writing.
  2. Modularity:
    1. Can be combined and reused to create complex I/O pipelines.
  3. Performance:
    1. Buffered streams reduce the overhead of frequent I/O operations.
  4. Error Handling:
    1. Streams like CheckedInputStream ensure data integrity.

Disadvantages of Filtered Byte Streams

  1. Complexity:
    1. Wrapping multiple streams can lead to verbose and less readable code.
  2. Limited Scope:
    1. They are byte-based and not suitable for handling character data. For text processing, character streams are preferred.

Conclusion

Filtered Byte Streams in Java provide a flexible and powerful way to enhance the capabilities of regular byte streams. By layering functionality, such as buffering or data integrity checks, developers can handle I/O more efficiently and securely. Understanding the use cases and implementation of these streams is key to mastering Java’s I/O framework.