I/O Filter Streams – Java I/O: Part I

I/O Filter Streams

An I/O filter stream is a high-level I/O stream that provides additional functionality to an underlying stream to which it is chained. The data from the underlying stream is manipulated in some way by the filter stream. The FilterInputStream and FilterOutputStream classes, together with their subclasses, define input and output filter streams. The subclasses BufferedInputStream and BufferedOutputStream implement filter streams that buffer input from and output to the underlying stream, respectively. The subclasses DataInputStream and DataOutputStream implement filter streams that allow binary representation of Java primitive values to be read and written, respectively, from and to an underlying stream.

Reading and Writing Binary Values

The java.io package contains the two interfaces DataInput and DataOutput, which streams can implement to allow reading and writing of binary representation of Java primitive values (boolean, char, byte, short, int, long, float, double). The methods for writing binary representations of Java primitive values are named writeX, where X is any Java primitive data type. The methods for reading binary representations of Java primitive values are similarly named readX. Table 20.3 gives an overview of the readX() and writeX() methods found in these two interfaces. A file containing binary values (i.e., binary representation of Java primitive values) is usually called a binary file.

Table 20.3 The DataInput and DataOutput Interfaces

TypeMethods in the DataInput interfaceMethods in the DataOutput interface
booleanreadBoolean()writeBoolean(boolean b)
charreadChar()writeChar(int c)
bytereadByte()writeByte(int b)
shortreadShort()writeShort(int s)
intreadInt()writeInt(int i)
longreadLong()writeLong(long l)
floatreadFloat()writeFloat(float f)
doublereadDouble()writeDouble(double d)
StringreadLine()writeChars(String str)
StringreadUTF()writeUTF(String str)

Note the methods provided for reading and writing strings. However, the recommended practice for reading and writing characters is to use character streams, called readers and writers, which are discussed in ยง20.3.

The filter streams DataOutputStream and DataInputStream implement the DataOutput and DataInput interfaces, respectively, and can be used to read and write binary representation of Java primitive values from and to an underlying stream. Both the writeX() and readX() methods throw an IOException in the event of an I/O error. In particular, the readX() methods throw an EOFException (a subclass of IOException) if the input stream does not contain the correct number of bytes to read. Bytes can also be skipped from a DataInput stream, using the skipBytes(int n) method which skips n bytes.

Click here to view code image

DataInputStream(InputStream in)
DataOutputStream(OutputStream out)

These constructors can be used to set up filter streams from an underlying stream for reading and writing Java primitive values, respectively.

File Streams – Java I/O: Part I

File Streams

The subclasses FileInputStream and FileOutputStream represent low-level streams that define byte input and output streams that are connected to files. Data can only be read or written as a sequence of bytes. Such file streams are typically used for handling image data.

A FileInputStream for reading bytes can be created using the following constructor:

Click here to view code image

FileInputStream(String name) throws FileNotFoundException

The file designated by the file name is assigned to a new file input stream.

If the file does not exist, a FileNotFoundException is thrown. If it exists, it is set to be read from the beginning. A SecurityException is thrown if the file does not have read access.

A FileOutputStream for writing bytes can be created using the following constructor:

Click here to view code image

FileOutputStream(String name) throws FileNotFoundException
FileOutputStream(String name, boolean append) throws FileNotFoundException

The file designated by the file name is assigned to a new file output stream.

If the file does not exist, it is created. If it exists, its contents are reset, unless the appropriate constructor is used to indicate that output should be appended to the file. A SecurityException is thrown if the file does not have write access or it cannot be created. A FileNotFoundException is thrown if it is not possible to open the file for any other reasons.

The FileInputStream class provides an implementation for the read() methods in its superclass InputStream. Similarly, the FileOutputStream class provides an implementation for the write() methods in its superclass OutputStream.

Example 20.1 demonstrates using a buffer to read bytes from and write bytes to file streams. The input and the output file names are specified on the command line. The streams are created at (1) and (2).

The bytes are read into a buffer by the read() method that returns the number of bytes read. The same number of bytes from the buffer are written to the output file by the write() method, regardless of whether the buffer is full or not after every read operation.

The end of file is reached when the read() method returns the value -1. The code at (3a) using a buffer can be replaced by a call to the transferTo() method at (3b) to do the same operation. The streams are closed by the try-with-resources statement. Note that most of the code consists of a try-with-resources statement with catch clauses to handle the various exceptions.

Example 20.1 Copying a File Using a Byte Buffer

Click here to view code image

/* Copy a file using a byte buffer.
   Command syntax: java CopyFile <from_file> <to_file> */
import java.io.*;
class CopyFile {
  public static void main(String[] args) {
    try (// Assign the files:
        FileInputStream fromFile = new FileInputStream(args[0]);       // (1)
        FileOutputStream toFile = new FileOutputStream(args[1]))  {    // (2)
      // Copy bytes using buffer:                                      // (3a)
      byte[] buffer = new byte[1024];
      int length = 0;
      while((length = fromFile.read(buffer)) != -1) {
        toFile.write(buffer, 0, length);
      }
      // Transfer bytes:
//    fromFile.transferTo(toFile);                                     // (3b)

    } catch(ArrayIndexOutOfBoundsException e) {
      System.err.println(“Usage: java CopyFile <from_file> <to_file>”);
    } catch(FileNotFoundException e) {
      System.err.println(“File could not be copied: ” + e);
    } catch(IOException e) {
      System.err.println(“I/O error.”);
    }
  }
}