Java I/O OverviewS2C Home « Java I/O Overview

Up until now we have been writing our output to the console, it's now time to look at the Java input and output mechanisms (I/O) in much more detail and we start three lessons on the subject with an overview of the various streams available in Java. Before we do this we need to look back to most of the programs we have written, including the very first program we wrote and interpret the following code System.out.println used in most of these programs.

System is a predefined class within java.lang that encapsulates different aspects of the JVM and provides access to the underlying system and out is the output stream connected to the console. The println() method displays the message passed to it on a new line. So when joined together a message is passed to the console and appears on a new line.

But what do we mean by output stream? To investigate this we need to take a closer look at the System class which contains three predefined fields named err, in and the field we are most familiar with out. Further inspection of these fields shows that they are public static and so can be used without an instance and are of the following types:

Name Type Description Default I/O Device
errPrintStreamThe "standard" error output stream.Console
inInputStreamThe "standard" input stream.Keyboard
outPrintStreamThe "standard" output stream.Console

So we can now see that these fields are of types InputStream and PrintStream and this is what Java I/O constitutes, class hierarchies of streams. Streams are named as an analogy to a stream of water that continues to flow; so you can think of Java streams as an abstraction, that produces or consumes flows of data. In this way we can conceptualise streams as data that flows into our programs as input streams, or flows out of our programs as output streams.

Java is made up of two types of streams, these being byte streams used for handling byte input and and output and character streams used for handling character input and and output. The primary reason Java uses streams for I/O is to make Java code independent of the input and output devices involved, thus making the peripheral device used and thus the coding to use it, transparent.

These streams are represented as classes of the java.io package and we will spend the rest of this lesson taking a high level look at this package and its classes to get a feel for how Java I/O hangs together. We will be looking at Byte Stream Classes and Character Stream Classes in much more detail in the next two lessons:

Byte StreamsTop

Byte streams are defined within two class hierarchies, one for input and one for output and represent byte stream classes which provide the tools to read and write binary data as a sequence of bytes.

  • The OutputStream class is the abstract superclass of all byte output streams
  • The InputStream class is the abstract superclass of all byte input streams

These classes define the characteristics that are common to byte input and byte output streams, which are implemented in the concrete subclasses of each hierarchy.

Byte Output Stream HierarchyTop

The diagram below shows most of the classes in the byte output stream hierarchy of which OutputStream class is the abstract superclass. Some subclasses of the FilterOutputStream class are not shown.

Outputstream hierarchy
Class Description
OutputStreamAbstract byte stream superclass which describes this type of output stream.
ByteArrayOutputStreamOutput byte stream that writes data to a byte array.
FileOutputStreamOutput byte stream that writes bytes to a file in a file system.
FilterOutputStreamOutput byte stream that implements OutputStream.
BufferedOutputStreamOutput byte stream that writes bytes to a buffered output stream.
DataOutputStreamOutput stream to write Java primitive data types.
PrintStreamConvenience output byte stream to add functionality to another stream, an example being to print to the console using print() and println().
ObjectOutputStreamOutput stream to write and serialize objects for reading using ObjectInputStream.
PipedOutputStreamPiped Output stream that is connected to a piped input stream to create a communication pipe.

Byte Input Stream HierarchyTop

The diagram below shows most of the classes in the byte input stream hierarchy of which InputStream class is the abstract superclass. Some subclasses of the FilterInputStream class are not shown.

Inputstream hierarchy
Class Description
InputStreamAbstract byte stream superclass which describes this type of input stream.
ByteArrayInputStreamInput byte stream that reads bytes from an internal byte array.
FileInputStreamInput byte stream that reads bytes from a file in a file system.
FilterInputStreamInput byte stream that implements InputStream.
BufferedInputStreamInput byte stream that reads bytes into an internal buffer before use.
DataInputStreamInput stream to reads Java primitive data types.
PushbackInputStreamInput byte stream containing functionality to return bytes to the input stream.
ObjectInputStreamInput stream to read and deserialize objects output and serialized using ObjectOutputStream.
PipedInputStreamPiped input stream that is connected to a piped output stream to create a communication pipe.
SequenceInputStreamConcatenation of two or more input streams read sequentially.

Character StreamsTop

Character streams are defined within two class hierarchies, one for input and one for output:

  • The Writer class is the abstract superclass of all character output streams
  • The Reader class is the abstract superclass of all character input streams

These classes define the characteristics that are common to character input and character output streams, which are implemented in the concrete subclasses of each hierarchy.

Character Output Stream HierarchyTop

The diagram below shows the classes in the character output stream hierarchy of which the Writer class is the abstract superclass.:

character input output hierarchy
Class Description
WriterAbstract character stream superclass which describes this type of output stream.
BufferedWriterBuffered output character stream.
CharArrayWriterCharacter buffer output stream.
FilterWriterAbstract character stream for writing filtered streams.
OuputStreamWriterOutput Stream that acts as a bridge for encoding byte streams from character streams.
FileWriterOutput stream for writing characters to a file.
PipedWriterPiped character output stream.
PrintWriterConvenience output character stream to add functionality to another stream, an example being to print to the console using print() and println().
StringWriterOutput stream for writing characters to a string.

Character Input Stream HierarchyTop

The diagram below shows the classes in the character input stream hierarchy of which the Reader class is the abstract superclass.:

character input stream hierarchy
Class Description
ReaderAbstract character stream superclass which describes this type of input stream.
BufferedReaderBuffered input character stream.
LineNumberReaderInput character stream that keeps a count of line numbers.
CharArrayReaderCharacter buffer input stream.
FilterReaderAbstract character stream for reading filtered streams.
PushbackReaderCharacter stream reader containing functionality to return characters to the input stream.
InputStreamReaderInput Stream that acts as a bridge for decoding byte streams into character streams.
FileReaderInput stream for reading characters from a file.
PipedReaderPiped character input stream.
StringReaderInput stream for reading characters from a string.

Other Java I/O ClassesTop

The diagram below shows some other pertinent classes in the java.io package not covered in the byte and character streams above:

Other java.io classes
Class Description
FileAbstract representation of file and directory pathnames.
FielDescriptorOpaque handle to the underlying machine-specific structure.
RandomAccessFileAllows reading and writing of bytes to a random access file.
StreamTokenizerInput stream to be parsed into 'tokens'.

The java.io.File ClassTop

We will finish this lesson with a talk about the File class that exists within the Java.io package and how we use objects of this class to represent an actual file and directory pathname that may or may not exist already on a hard drive. A File object doesn't contain the file in question or any data associated with the file, it just acts like a pointer to said file and can be a relative or absolute pathname:

  1. Relative URL - The common use of a relative URL is by omitting the protocol and server name, as documents generally reside on the same server. So this would be directoryName/fileName.extension.
    For example the relative url images/runwhile.webp
  2. Absolute URL - An absolute url is the complete address of the resource.
    For example the absolute url https://server2client.com/images/runwhile.webp

Before we get look at some of the methods of the File class, lets clarify what we mean by a File object pointing to a file:


/*
  Create a file object that points to a file
*/
class TestFileCreation {
    public static void main(String[] args) {
        File newFile  = new File("MyFile.txt");
    }
}

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

run test File Creation

The above screenshot shows the output of compiling the TestFileCreation class. The compiler cannot find the File object type. This is because the File class exists within the java.io package and so we need to either qualify usage as in:


/*
  Create a file object that points to a file
*/
class TestFileCreation {
    public static void main(String[] args) {
        java.io.File newFile  = new java.io.File("MyFile.txt"); // Qualifying File gives clean compile
    }
}

Or we can import the java.io package as in the code below. We will use the import keyword over qualifying the names in our examples as we think it is easier and less error-prone:


/*
  Create a file object that points to a file
*/
import java.io.File; // Just import the file class from java.io package

class TestFileCreation {
    public static void main(String[] args) {
        File newFile  = new File("MyFile.txt");
    }
}

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

run test File Creation2

The above screenshot shows the output of running the TestFileCreation class and then doing a dir command in the   c:\_APIContents2 directory. As you can see we haven't created a physical file called MyFile.txt, we just made a File object to point to a file that may exist called MyFile.txt in the relative path we are in.

This time we will create a phsical file and directory and use some File methods:


/*
  Create a file object that points to a directory
*/
import java.io.File; // Just import the file class from java.io package
import java.io.IOException; // Import the IOException class from java.io package

class TestFileCreation2 {
    public static void main(String[] args) {
        File newFile  = new File("MyFile.txt");
        if (newFile.exists()) { // Check to see if Myfile.txt already exists
            System.out.println("Myfile.txt already exists.");
        } else {
            System.out.println("Try to create Myfile.txt");
            try {
                newFile.createNewFile(); // Create a file called Myfile.txt
                System.out.println("We created Myfile.txt");
            }
            catch (IOException ex) {
                System.out.println("We caught exception: " + ex);
            }
        }
        File newDir  = new File("JavaIO");
        newDir.mkdir(); // Create a directory called JavaIO  
       if (newDir.isDirectory()) { // true as we created a directory         
            System.out.println("We created a directory.");
            System.out.println(newDir.getAbsolutePath());
            System.out.println(newDir.getParent());
        }
    }
}

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

run test File Creation3

The above screenshot shows the output of running the TestFileCreation2 class and then doing a dir command in the   c:\_APIContents2 directory.

Firstly we created a new File object and then check to see if this file already phsically exists using the exist() method. If the file doesn't actually exist we physically create the file on disk using the createNewFile() method which can throw an IOException which we deal with. We then print a message showing the file was created.

Secondly we create a new File object but this time we make a directory. We then physically create a directory on disk called JavaIO using the mkdir() method and test to see if it exists using the isDirectory() method. We then print a message showing the directory was created and print out the absolute path using the getAbsolutePath() method. The program then prints null from the getParent() method as we didn't use a parent directory when creating the JavaIO directory.

As we can see from doing the dir command in the   c:\_APIContents2 directory we have indeed created a file called Myfile.txt and a directory called JavaIO.

There are plenty of other methods in the java.io.File Class to use for creation and deletion of files and directories so make sure to look at the Oracle docs for this.

Lesson 4 Complete

In this lesson we started three lessons on the subject of Java I/O with an overview of the various streams available in Java.

What's Next?

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

go to home page Homepage go to top of page Top