Byte Stream ClassesS2C Home « Byte Stream Classes

Now we have got an overview of the class hierarchies involved in Java I/O its time to investigate these classes in more detail. In our second lesson on Java I/O we take a closer look at some of the byte stream classes that are available for our use in the java.io package and how we use them.

The byte stream classes are the original input and output streams which were shipped with JDK 1.0. This is the reason why System.in, System.out and System.err use the InputStream and PrintStream types from the byte stream classes and not the character stream classes as you would expect. The character stream classes were introduced to the language in JDK 1.1.

The java.io.OutputStream ClassTop

At the top of the byte output stream hierarchy is the java.io.OutputStream abstract superclass which defines a basic set of output functions that all byte output stream classes have. These methods allow us to flush and write bytes within the byte output stream as well as close the stream when we finish our processing. All methods within the java.io.OutputStream class can throw an IOException.

The table below shows the declarations of all the methods in the java.io.OutputStream class:

Method Declaration Description
public void close()Closes output stream and release any system resources associated with it.
public void flush()Flushes output stream and forces any buffered output bytes to be written out.
public abstract void write(int b)Writes a single byte of data specified by b to the output stream.
public void write(bytes[] b) Writes b bytes of data from b array.
public void write(bytes[] b, int off, int len) Writes len bytes of data from b array starting from off.

write(bytes[]) ExampleTop

Lets see how we could use the write(bytes[]) method above to write a sequence of characters to the console:


/*
  Write character sequence to the console
*/
import java.io.IOException; // Import the IOException class from java.io package

class WriteToConsole {
    public static void main(String[] args) {
       try {
           byte consoleOut[] = new byte[]{'J','a','v','a','6'};
           System.out.write(consoleOut);
       } 
       catch (IOException ex) {
           System.out.println("Caught IOException: " + ex);
       }
    }
}

Save, compile and run the WriteToConsole test class in directory   c:\_APIContents2 in the usual way.

run write o console

The above screenshot shows the output of compiling and running the WriteToConsole class. Using System.out.print and System.out.println are a lot easier to use but you may need to write to the console this way, for some reason.

The java.io.FileOutputStream ClassTop

We saw above how we can write bytes to the console using methods from the java.io.OutputStream class. This doesn't really offers us anything practical when it comes to storing information on the underlying file system. Luckily for us the subclasses in the byte output stream hierarchy give us ways to persist our data. In this part of the lesson we examine the java.io.FileOutputStream class which allows us to output data to a file on the system. This class offers us constuctors to write to physical files represented by File, FileDescriptor and String objects that point to the actual files on the system.

Writing To A FileTop

For our example of using the java.io.FileOutputStream class we will create a File object in our working directory and write some data to the file:


/*
  Write character sequence output to a file using FileOutputStream
*/
import java.io.*; // Import all file classes from java.io package

class TestFileOutputStream {
    public static void main(String[] args) {
        byte someData[] = new byte[]{'J','a','v','a','6'}; // Our output data
        FileOutputStream fos; // Our FileOutputStream
        File newFile  = new File("FileOutputStream.txt");
        if (newFile.exists()) { // Check to see if FileOutputStream.txt already exists
            System.out.println("FileOutputStream.txt already exists.");
        } else {
            System.out.println("Try to create FileOutputStream.txt");
            try {
                newFile.createNewFile(); // Create a file called FileOutputStream.txt
                System.out.println("We created FileOutputStream.txt");
            }
            catch (IOException ex) {
                System.out.println("We caught exception: " + ex);
            }
        }
         // Open FileOutputStream.txt and output some data to it
        try {
            fos = new FileOutputStream(newFile); // Create a stream to write to FileOutputStream.txt
            System.out.println("FileOutputStream fos has been opened.");
            for (int i=0;i<someData.length;i++) {
                System.out.println("Writing byte " + i + " to file");
                fos.write(i);
            }
            fos.close();
        }
        catch (FileNotFoundException ex) {
            System.out.println("Exception opening FileOutputStream.txt : " + ex);
        }
        catch (IOException ex) {
            System.out.println("We caught exception to fos: " + ex);
        }
    }
}

Save, compile and run the TestFileOutputStream test class in directory   c:\_APIContents2 in the usual way.

run test fileoutputstream

The above screenshot shows the output of compiling and running the TestFileOutputStream class. We print some messages to the console as we create open and write to the file.

The java.io.DataOutputStream ClassTop

Up until this point in the lesson we have been outputting bytes either to the console or a file. What you may not be aware of is we are passing across the low-end 8 bits of data, which means that any primitive type we pass will only have those bits passed across. Of course this is fine when we actually pass a Byte across but for other primitive types we are not passing across an actual representation of that primitive value, just the low-end 8 bits of it. If you read in the previous examples file "FileOutputStream.txt" and cast the bytes back to char primitive you will see some strange symbols displayed instead of 'java'. This is because we have lost the second lot of bits which make up a Unicode character. Things get even worse if you try and write and then read back in other primitive types which can take up to 8 bytes of storage.

If you look at the byte output stream hierarchy, the FilterOutputStream class is a direct subclass of the OutputStream class that implements all its methods. The FilterOutputStream class is the superclass of all classes that filter output streams. These substreams sit on top of existing output streams such as the FileOutputStream and use the stream as a basic data sink, possibly modifying the data along the way or providing enhanced functionality. Using multiple streams in combination is known as wrapping as essentially we wrap one stream within another.We will be using the java.io.DataOutputStream subclass in our example below which takes an instance of FileOutputStream in its instantiation. This class allows us to output primitive data types to an output stream.

Writing Binary Data To A FileTop

Our example using the java.io.DataOutputStream class will highlight the way we use a substream within a stream. We will create a File object in our working directory and write some primitive data types to that file:


/*
  Write binary data to a file using DataOutputStream
*/
import java.io.*; // Import all file classes from java.io package

class TestDataOutputStream {
    public static void main(String[] args) {
         // Our output data
        int i = 128;
        long l = 128128;
        float f = 12.8f;
        double d= 128.128;
        DataOutputStream dos; // Our DataOutputStream
        File newFile  = new File("DataOutputStream.txt");
        if (newFile.exists()) { // Check to see if DataOutputStream.txt already exists
            System.out.println("DataOutputStream.txt already exists.");
        } else {
            System.out.println("Try to create DataOutputStream.txt");
            try {
                newFile.createNewFile(); // Create a file called DataOutputStream.txt
                System.out.println("We created DataOutputStream.txt");
            }
            catch (IOException ex) {
                System.out.println("We caught exception: " + ex);
            }
        }
        try {
             // Open DataOutputStream using a FileOutputStream as a 'wrapper'
            dos = new DataOutputStream(new FileOutputStream(newFile));
            System.out.println("DataOutputStream dos has been opened.");
            System.out.println("Writing int " + i + " to file");
            dos.writeInt(i);
            System.out.println("Writing long " + l + " to file");
            dos.writeLong(l);
            System.out.println("Writing float " + f + " to file");
            dos.writeFloat(f);
            System.out.println("Writing double " + d + " to file");
            dos.writeDouble(d);
            dos.close();
        }
        catch (FileNotFoundException ex) {
            System.out.println("Exception opening DataOutputStream.txt : " + ex);
        }
        catch (IOException ex) {
            System.out.println("We caught exception to dos: " + ex);
        }
    }
}

Save, compile and run the TestDataOutputStream test class in directory   c:\_APIContents2 in the usual way.

run test dataoutputstream

The above screenshot shows the output of compiling and running the TestDataOutputStream class. We print some messages to the console as we create open and write some primitives to the file.

The java.io.ObjectOutputStream ClassTop

In our final look at the classes in the byte output stream hierarchy we look at writing objects to persistent storage using the java.io.ObjectOutputStream class. We can overlay this stream with the FileOutputStream to permanantly persist object state to our hard drives which we can read back at a later time using the java.io.ObjectInputStream class.

Writing Objects To A FileTop

Our example using the java.io.ObjectOutputStream class will highlight the way we use a substream within a stream. We will create a File object in our working directory and write a String and Date object to that file:


/*
  Write objects to a file using ObjectOutputStream
*/
import java.io.*; // Import all file classes from java.io package
import java.util.Date; // Import Date class from java.util package

class TestObjectOutputStream {
    public static void main(String[] args) throws IOException {
        ObjectOutputStream oos; // Our ObjectInputStream
        
        File newFile  = new File("ObjectOutputStream.txt");
        if (newFile.exists()) { // Check to see if ObjectOutputStream.txt already exists
            System.out.println("ObjectOutputStream.txt already exists.");
        } else {
            System.out.println("Try to create ObjectOutputStream.txt");
            try {
                newFile.createNewFile(); // Create a file called ObjectOutputStream.txt
                System.out.println("We created ObjectOutputStream.txt");
            }
            catch (IOException ex) {
                System.out.println("We caught exception: " + ex);
            }
        }
        try {
             // Open ObjectOutputStream using a FileOutputStream as a 'wrapper'
            oos = new ObjectOutputStream(new FileOutputStream(newFile));
            oos.writeObject("Today");
            System.out.println("String object written");
            oos.writeObject(new Date());
            System.out.println("Date object written");
    
            oos.close();
        }
        catch (FileNotFoundException ex) {
            System.out.println("Exception opening ObjectOutputStream.txt : " + ex);
        }
        catch (IOException ex) {
            System.out.println("We caught exception to oos: " + ex);
        }
    }
}

Save, compile and run the ObjectOutputStream test class in directory   c:\_APIContents2 in the usual way.

run test objectoutputstream

The above screenshot shows the output of compiling and running the TestDataOutputStream class. We print some messages to the console as we create open and write a String and Date object to a file.

The java.io.InputStream ClassTop

At the top of the byte input stream hierarchy is the java.io.InputStream abstract superclass which defines a basic set of input functions that all byte input stream classes have. These methods allow us to allocate, mark, read, reset and skip bytes within the byte input stream as well as close the stream when we finish our processing. All methods within the java.io.InputStream class apart from the mark() and markSupported() methods can throw an IOException.

The table below shows the declarations of all the methods in the java.io.InputStream class:

Method Declaration Description
public int available())Return the number of bytes currently available that can be read or skipped.
public void close()Closes input stream and release any system resources associated with it.
public void mark(int readlimit)Mark current stream position to which we can return until readlimit has been reached.
public boolean markSupported()Returns true if invoking stream supports mark() and reset() methods.
public abstract int read()Reads next byte of data from input stream or -1 if end of file encountered.
public int read(bytes[] b) Reads b bytes of data into b array.
public int read(bytes[] b, int off, int len) Reads len bytes of data into b array starting from off.
public void reset()Reset the input pointer to the last mark() position.
public long skip(long skipBytes)Skip number of bytes specified by skipBytes and return skipBytes.

read() ExampleTop

Lets see how we could use the read() method above to get byte input from the keyboard:


/*
  Read byte from keyboard
*/
import java.io.IOException; // Import the IOException class from java.io package

class ReadFromKB {
    public static void main(String[] args) {
       try {
           System.out.println("Press a key and then press Enter");
           System.out.println("You pressed the " + System.in.read() + " key.");
       } 
       catch (IOException ex) {
           System.out.println("Caught IOException: " + ex);
       }
    }
}

Save, compile and run the ReadFromKB test class in directory   c:\_APIContents2 in the usual way.

run read from keyboard

The above screenshot shows the output of compiling and running the ReadFromKB class. The output shows entry of a small 'g' and this being processed by our program as Unicode decimal '103'.

read(bytes[]) ExampleTop

Lets see how we could use the read(bytes[]) method above to get a sequence of bytes from the keyboard:


/*
  Read character sequence from keyboard
*/
import java.io.IOException; // Import the IOException class from java.io package

class ReadFromKB2 {
    public static void main(String[] args) {
       try {
           byte kbIn[] = new byte[15];
           System.out.println("Type a character sequence and then press Enter");
           System.in.read(kbIn);
           System.out.println("You typed in ");
           for (int i=0;i<kbIn.length;i++) {
               System.out.print(kbIn[i]);
           }
           System.out.print(" ... ");
           for (int i=0;i<kbIn.length;i++) {
               System.out.print((char) kbIn[i]);
           }
       } 
       catch (IOException ex) {
           System.out.println("Caught IOException: " + ex);
       }
    }
}

Save, compile and run the ReadFromKB2 test class in directory   c:\_APIContents2 in the usual way.

run read buffer from keyboard

The above screenshot shows the output of compiling and running the ReadFromKB2 class. The output shows entry of string 'javaTutor' and this being read in and processed by our program and printed out as Unicode decimal and cast to char primitive type.

The java.io.FileInputStream ClassTop

We saw above how we can read bytes from the keyboard using methods from the java.io.InputStream class. This doesn't really offers us anything practical when it comes to reading information from the underlying file system. Luckily for us the subclasses in the byte input stream hierarchy give us ways to read our persisted data. In this part of the lesson we examine the java.io.FileInputStream class which offers us methods to read existing files on the system.

Reading From A FileTop

For our example of using the java.io.FileInputStream class we will we will create a File object to read the FileOutputStream.txt file we created in the java.io.FileOutputStream section above:


/*
  Read input a file using FileInputStream
*/
import java.io.*; // Import all file classes from java.io package

class TestFileInputStream {
    public static void main(String[] args) throws IOException {
        int i;
        FileInputStream fis; // Our FileOutputStream
        File newFile  = new File("FileOutputStream.txt");
        if (newFile.exists()) { // Check to see if FileOutputStream.txt already exists
            System.out.println("FileOutputStream.txt already exists.");
        } else {
            System.out.println("Did you run the java.io.FileOutputStream example?");
            throw new IOException();
        }
         // Open FileInputStream.txt and read data from it
        try {
            fis = new FileInputStream(newFile); // Create a stream to read from FileOutputStream.txt
            System.out.println("FileInputStream fis has been opened.");
            do {
                i = fis.read();
                if (i != -1) {  // The -1 value denotes the end of file condition
                    System.out.println("We read in character " + i);
                }
            } while (i != -1); 

            fis.close();
        }
        catch (FileNotFoundException ex) {
            System.out.println("Exception opening FileOutputStream.txt : " + ex);
        }
        catch (IOException ex) {
            System.out.println("We caught exception to fis: " + ex);
        }
    }
}

Save, compile and run the TestFileInputStream test class in directory   c:\_APIContents2 in the usual way.

run test fileinputstream

The above screenshot shows the output of compiling and running the TestFileInputStream class. We print some messages to the console as we create open and read from the file.

The java.io.DataInputStream ClassTop

If you look at the byte input stream hierarchy, the FilterInputStream class is a direct subclass of the InputStream class that implements all its methods. The FilterInputStream class is the superclass of all classes that filter input streams. These substreams sit on top of existing input streams such as the FileInputStream and are a way or providing additional functionality to the stream. Using multiple streams in combination is known as wrapping as essentially we wrap one stream within another. We will be using the java.io.DataInputStream subclass in our example below which takes an instance of FileInputStream in its instantiation. This class allows us to read primitive data types from an input stream.

Reading Binary Data From A FileTop

Our example using the java.io.DataInputStream class will highlight the way we use a substream within a stream. We will create a File object in our working directory and read some primitive data types from the physical representation of that file:

For our example of using the java.io.DataInputStream class we will we will create a File object to read the DataOutputStream.txt file we created in the java.io.DataOutputStream section above:


/*
  Read binary data from a file using DataInputStream
*/
import java.io.*; // Import all file classes from java.io package

class TestDataInputStream {
    public static void main(String[] args) throws IOException {
        DataInputStream dis; // Our DataInputStream
        
        File newFile  = new File("DataOutputStream.txt");
        if (newFile.exists()) { // Check to see if DataOutputStream.txt already exists
            System.out.println("DataOutputStream.txt already exists.");
        } else {
            System.out.println("Did you run the java.io.DataOutputStream example?");
            throw new IOException();
        }
        try {
             // Open DataInputStream using a FileInputStream as a 'wrapper'
            dis = new DataInputStream(new FileInputStream(newFile));
            System.out.println("DataInputStream dis has been opened.");
            int i = dis.readist();
            System.out.println("int i = " + i);
            long l = dis.readLong();
            System.out.println("long l = " + l);
            float f = dis.readFloat();
            System.out.println("float f = " + f);
            double d = dis.readDouble();
            System.out.println("double d = " + d);

            dis.close();
        }
        catch (FileNotFoundException ex) {
            System.out.println("Exception opening FileOutputStream.txt : " + ex);
        }
        catch (IOException ex) {
            System.out.println("We caught exception to dis: " + ex);
        }
    }
}

Save, compile and run the TestDataInputStream test class in directory   c:\_APIContents2 in the usual way.

run test datainputstream

The above screenshot shows the output of compiling and running the TestDataOutputStream class. We print some messages to the console as we create open and read the primitives from the file.

The java.io.ObjectInputStream ClassTop

In our final look at the classes in the byte input stream hierarchy we look at reading objects that were serialized and persisted to storage using the java.io.ObjectOutputStream class.

Reading Objects From A FileTop

For our example of using the java.io.ObjectInputStream class we will we will create a File object to read the ObjectOutputStream.txt file we created in the java.io.ObjectOutputStream section above:


/*
  Read serialized objects from a file using ObjectInputStream
*/
import java.io.*; // Import all file classes from java.io package
import java.util.Date; // Import Date class from java.util package

class TestObjectInputStream {
    public static void main(String[] args) throws IOException {
        ObjectInputStream ois; // Our ObjectInputStream
        
        File newFile  = new File("ObjectOutputStream.txt");
        if (newFile.exists()) { // Check to see if ObjectOutputStream.txt already exists
            System.out.println("ObjectOutputStream.txt already exists.");
        } else {
            System.out.println("Did you run the java.io.ObjectOutputStream example?");
            throw new IOException();
        }
        try {
             // Open ObjectInputStream using a FileInputStream as a 'wrapper'
            ois = new ObjectInputStream(new FileInputStream(newFile));
            String today = (String) ois.readObject();
            System.out.println(today);
            Date date = (Date) ois.readObject();
            System.out.println(date);

            ois.close();
        }
        catch (ClassNotFoundException ex) {
            System.out.println("Class Exception: " + ex);
        }
        catch (FileNotFoundException ex) {
            System.out.println("Exception opening ObjectOutputStream.txt : " + ex);
        }
        catch (IOException ex) {
            System.out.println("We caught exception to ois: " + ex);
        }
    }
}

Save, compile and run the ObjectInputStream test class in directory   c:\_APIContents2 in the usual way.

run test objectinputstream

The above screenshot shows the output of compiling and running the TestObjectInputStream class. We print some messages to the console as we deserialize and read back in the String and Date objects that were serialized in the java.io.ObjectOutputStream section above.

Lesson 5 Complete

In this lesson we took a closer look at some of the byte stream classes that are available in Java and how we use them.

What's Next?

In the next lesson we look at some of the Character stream classes that are available in Java and how we use them.

go to home page Homepage go to top of page Top