BufferedInputStream and BufferedOutputStream in Java

In Java, the BufferedInputStream and BufferedOutputStream classes are used to improve the efficiency of input and output operations by adding a buffer between the program and the input/output source (such as a file or network connection). By buffering the data, fewer I/O operations are performed, which can significantly improve performance, especially for reading and writing large amounts of data.

What is a Buffer?

A buffer is a temporary storage area in memory that holds data before it is processed. Instead of reading or writing data byte-by-byte (which can be slow), a buffer reads or writes data in larger blocks, minimizing the number of interactions with the underlying system (such as a hard drive).

  • BufferedInputStream: Reads data from the source (like a file) into a buffer, and then the program reads data from the buffer, improving performance.
  • BufferedOutputStream: Writes data to the buffer first, and when the buffer is full or flushed, it writes all the data to the destination (like a file) in one go, reducing the number of I/O operations.

BufferedInputStream Class

BufferedInputStream is a subclass of FilterInputStream and adds buffering to an input stream. It wraps around other input streams, such as FileInputStream, and provides efficient reading of data by reducing the number of I/O operations.

How Does It Work?

  • Without buffering: The program reads data from the input stream byte-by-byte, leading to frequent I/O operations, which are slow.
  • With buffering: BufferedInputStream reads a large chunk of data (default buffer size is 8 KB) from the input stream into a buffer. Subsequent reads take data from the buffer, which is faster.

Constructors of BufferedInputStream:

BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in, int size)  // in: input stream, size: buffer size
Code Example
Output

Explanation:

  • BufferedInputStream: Wraps the FileInputStream, adding a buffer for efficient reading.
  • bis.read(): Reads data from the buffer instead of directly from the file, improving performance.
  • The program prints the contents of the file example.txt character by character.

BufferedOutputStream Class

BufferedOutputStream is a subclass of FilterOutputStream and adds buffering to an output stream. It wraps around other output streams, such as FileOutputStream, and writes data to the buffer first, then to the destination when the buffer is full or explicitly flushed.

How Does It Work?

  • Without buffering: The program writes data byte-by-byte to the output stream, causing frequent writes to the file, which is slow.
  • With buffering: BufferedOutputStream collects the data in a buffer. When the buffer is full (default size is 8 KB) or explicitly flushed, it writes the entire buffer to the output stream in one operation, reducing the number of writes.

Constructors of BufferedOutputStream:

BufferedOutputStream(OutputStream out)
BufferedOutputStream(OutputStream out, int size)  // out: output stream, size: buffer size
Code Example

Explanation:

  • BufferedOutputStream: Wraps the FileOutputStream, adding a buffer for efficient writing.
  • bos.write(): Writes data to the buffer instead of directly to the file.
  • bos.flush(): Ensures that any remaining data in the buffer is written to the file.
  • The program writes the string "BufferedOutputStream improves writing efficiency!" to the file output.txt.

How BufferedInputStream and BufferedOutputStream Improve Performance

  • BufferedInputStream reduces the number of read operations by filling a buffer from the input stream in one go, and subsequent reads are done from the buffer, which is faster.
  • BufferedOutputStream reduces the number of write operations by storing data in a buffer and writing the entire buffer to the output stream in one operation, which is more efficient than writing data byte-by-byte.

Without buffering, every read() or write() operation would result in an I/O operation, which is relatively slow. Buffering minimizes these I/O operations by grouping them into larger chunks, thereby improving the program's performance.


Key Methods of BufferedInputStream and BufferedOutputStream

BufferedInputStream Methods

  • read(): Reads a single byte from the input stream.
  • read(byte[] b, int off, int len): Reads bytes into the specified portion of the byte array.
  • available(): Returns an estimate of the number of bytes that can be read without blocking.
  • mark(int readlimit): Marks the current position in the input stream for later resetting.
  • reset(): Resets the input stream to the previously marked position.
  • close(): Closes the stream and releases system resources.

BufferedOutputStream Methods

  • write(int b): Writes a single byte to the output stream.
  • write(byte[] b, int off, int len): Writes bytes from the specified byte array to the output stream.
  • flush(): Forces any buffered output bytes to be written to the underlying output stream.
  • close(): Closes the stream, flushing any remaining buffered output.

Differences Between BufferedInputStream/BufferedOutputStream and FileInputStream/FileOutputStream

FeatureFileInputStream / FileOutputStreamBufferedInputStream / BufferedOutputStream
PerformanceSlower, as data is read/written byte-by-byteFaster, as data is read/written in larger chunks (buffered)
Default Buffer SizeNo buffering by default8192 bytes (8 KB), can be customized
Use CaseSuitable for small amounts of dataSuitable for large amounts of data, improves performance
Typical OperationsDirect access to file or network streamBuffered access to file or network stream

Examples Combining FileInputStream/FileOutputStream with BufferedInputStream/BufferedOutputStream

Copying a File Using Buffered Streams

This example demonstrates copying a file using BufferedInputStream and BufferedOutputStream to improve efficiency.

Code Example

Explanation:

  • BufferedInputStream: Reads data from sourceFile.txt in chunks, improving the efficiency of reading.
  • BufferedOutputStream: Writes data to destinationFile.txt in chunks, improving the efficiency of writing.
  • A buffer of 1 KB is used to read from the source file and write to the destination file, reducing the number of read/write operations.