Java Input and Output (I/O)

Introduction

Input is any information that is needed by your program to complete its execution. There are many forms that program input may take. Some programs use graphical components like a popup dialog box to accept and return the character string that is typed by the user. You are certainly familiar with programs that are controlled simply by clicking the mouse in a specific area of the screen. Still other programs, like word processing programs, get some of their input from a file that is stored on the computer's floppy or hard disk drive. Some programs, like web browsers, get their data from a network connection, while others get data from devices like scanners, digital cameras and microphones. The possibilities are limited only by computer scientists' imagination.

Output is any information that the program must convey to the user. The information you see on your computer screen is being output by one or more programs that are currently running on your computer. When you decide to print a document, a program is told to send some output to the printer. Any sound that your computer makes is because some program sent output to the speakers on your computer. The possibilities for program output are also limited only by our imaginations.

Throughout the semester, we have been performing input and through the use of a Scannerobject connected to System.in and output through the use of a PrintStream object (System.out).

There are several potential error conditions that may occur when a program needs to get input from the user. If a user enters letters when a program is expecting numbers, an exception  (error) will occur if the program assumes incorrectly that it has a valid integer to use in calculations. Programs must be written to survive bad input by the user. One way to do this is to ensure that only valid input is accepted.

Standard Java classes do not ensure that only valid input is accepted. They are designed to be very flexible to support the wide variety of input and output options available now and in the future. This flexibility comes at the cost of increased complexity.

Console Input

The console window is the window that is automatically launched when you run a program from within Eclipse. Console input is any input that is entered in the console window instead of typing it into a field or dialog box that pops up in a window. For example, when the nextLine method is called, the program waits for the user to enter information. Whatever the user types is returned to the program in the form of a String object.

There are many ways to get information from the user. In many cases, the user must be told that they should enter some information. This is known as prompting the user. A user prompt is a line of text that is output to the user that explains what information they should input next. We can prompt the user by displaying information in a dialog box, a program frame, or even the console window. All programs that require the user to input information while the program is running must prompt the user for that information in some manner.

When a program is waiting for input at the console, there is sometimes a blinking cursor in the console window indicating that the user should type some information. But, this is not always the case. The user will only know what information to type if the program describes that information in the form of a user prompt. (See Console Output for more information on user prompts.)

The use of several of the Java I/O classes may be required to successfully receive input that is typed by the user. The java.io package contains most, if not all, of the classes you will need to use. The java.util package also contains some classes that are useful for input and output. Don't worry, you won't need to use all 50+ classes. But, you will need to learn about and use at least a couple of them. Either use the fully qualified name shown or import the specified package to use either of these classes.

The Scanner class has a method called nextLine that returns a line of text as typed by the user. There are two available constructors for creating a Scanner object. For console input, we will use the one that requires only one argument, an instance of an InputStream object.

We will use the System.in object as our InputStream object and then use that object to create an instance of the Scanner class.

Steps for console based user input:

  1. Use the System.in object to create a Scanner object.
  2. Display a prompt to the user for the desired data.
  3. Use the Scanner object to read a line of text from the user.
  4. Do something interesting with the input received from the user.

Would you like to see some code?  I thought so. Here it is:

    // 1. Create a Scanner using the InputStream available.
    Scanner scanner = new Scanner( System.in );

    // 2. Don't forget to prompt the user
    System.out.print( "Type some data for the program: " );

    // 3. Use the Scanner to read a line of text from the user.
    String input = scanner.nextLine();

    // 4. Now, you can do anything with the input string that you need to.
    // Like, output it to the user.
    System.out.println( "input = " + input );

That's a lot of code for one line of input. Is there a shorter way?

Yes. Subtle bugs are introduced into your program when you connect more than one Scannerobject to the single InputStream object System.in. So, Java programmers create only one instance of the Scanner connected to System.in for use throughout their entire program. All keyboard operations will use that single shared Scanner object. The code below is placed with other class data members and is not inside any method.

    // 1. Create a single shared Scanner object for keyboard input.
    //    This must be done in only one class of your program.
    //    All keyboard input must be handled through that one class.
    private static Scanner scanner = new Scanner( System.in );

I added the above code to my program and I get compiler errors!

Did you remember to import the java.util.Scanner class?  The Scanner class is not in the standard java.lang package. You must import the java.util.Scanner class to declare and create instances of the Scanner class. You must import the java.io package to declare and create instances of any of the other Java I/O classes discussed in this document. It's easiest to add the import java.util.*; statement (and, if you are using the other Java I/O classes, the import java.io.*; statement) to your list of other import statements. Here's a complete program example that prompts the user for input and then repeats that data to the console window:

    import java.util.Scanner;  // needed for Scanner

    /** A Java program that demonstrates console based input and output. */
    public class MyConsoleIO 
    {
        // Create a single shared Scanner for keyboard input
        private static Scanner scanner = new Scanner( System.in );

        // Program execution starts here
        public static void main ( String [] args )
        {
            // Prompt the user
            System.out.print( "Type some data for the program: " );


            // Read a line of text from the user.
            String input = scanner.nextLine();

            // Display the input back to the user.
            System.out.println( "input = " + input );

        } // end main method

    } // end MyConsoleIO class

Integer input

Getting data from the user isn't so hard after all. But, it does require some additional work. There may be even more work to do, if you want to get an integer (or other numeric value) from the user. If the user types in "123", that will be still be returned as a String object by the nextLine method of Scanner. You will need to parse (convert) the String object into an int value if you wish to store it in an int variable or data member. Here's one way to do this:

  1. Get a String of characters that is in an integer format, e.g.,  "123".
    String input = scanner.nextLine();  // from console input example above.

  2. Use the Integer class to parse the string of characters into an integer.
    int number = Integer.parseInt( input );  // converts a String into an int value

    The Integer class contains conversion methods for changing String data into int values and vice versa. The Integer class is one of several wrapper classes that are defined in the standard Java API. Wrapper classes have class methods for parsing and are also used when you need to store a primitive value as an object.

    In our case, we needed to convert a String object into an int value. The parseInt method of the Integer class performs this action. Be sure to review the Integer class javadoc for more information about this and other methods of the Integer class.

Here's another way to do this:

  1. Read the next available input as an int value.
    int number = scanner.nextInt();  // from console input example above.

As you can see, the Scanner class contains a method named nextInt that returns the next input data available as an int value, that is, if the next input in the input stream is a valid integer format. If the next input is not a valid integer format, an InputMismatchException is thrown.

You may be wondering why are there two ways to read integers from the user. This flexibility allows you, the programmer, the option of which form is best for your program. The correct form to use depends upon what you wish to do with the rest of the line that remains after an integer is read from the current input line. The first example should be used if the only thing available on the current input line is the integer value. The second example should be used if there are multiple data values to read on the same input line.

What if the user types letters instead of digits?

The parseInt method declares that it may throw a NumberFormatException. If the user types any string of characters that can't be parsed into an int value, a NumberFormatException will be thrown and the program will crash. That can't be a good thing! But, there is something that you as the programmer can do to keep your program from crashing. You can catch the NumberFormatException. If you don't know what an exception is, read about them in Java Exceptions. There is an example on catching a FileNotFoundException.

Console Output

We have used System.out.print(...) and System.out.println(...) statements for displaying simple text messages to the user. This is an important output alternative, since graphic user interface (GUI) objects are not readily available in some programming environments. You may of course write your own GUI classes if they're not available, but that is beyond the scope of this course. It is much more likely that you will simply use the available output options of the programming environment that you are working in.

Most programming languages have the ability to display a string of characters to the screen or some other standard display device. We call this console output because the string of characters appears in a console window. The System.out object is an instance of the PrintStream class, which is a type of OutputStream.

Streams

A stream object is used to store information needed to connect a computer program to an input or output device. There is a PrintStream object that adds functionality to output streams. The PrintStream class extends the OutputStream class and contains definitions for all of the versions of the print and println methods that we use to display information like user prompts or results of calculations.

Console output in Java is very easy because the print and println methods will work with any type of data. There is a separate version of each of these methods in the PrintStream class so that this is possible. There is also a version of the print and println methods that will print information for any object. But, how did we get a PrintStream object in the first place?

The java.lang.System class creates three different I/O streams automatically for us when our application begins execution. Each of these streams is public and static so that we can access them directly without having to create an instance of the System class. We have already used the InputStream object named System.in in the discussion on console input. The other two stream objects are named System.out and System.err.  Each of these objects is an instance of the PrintStream class and is available for use in displaying information to the computer screen.

For example, if the following variables are defined,

    int x = 3;
    double rate = 5.5;
    boolean playing = true;
    String phrase = "The winner is ";

they can all be printed using print or println as follows:

    System.out.print( "x = " + x + " rate = " );
    System.out.println( rate );
    System.out.println( "playing = " + playing );
    System.out.println( phrase + "Deb" );

We can also print other types of data, including other objects, using the print and println methods. The following code fragment shows the command syntax for printing a Wanderer object. The class name Wanderer is used as an example. You can replace Wanderer with any class name that is defined in your program.

    Wanderer wanderer1 = new Wanderer( "Wilma", Color.orange );
    System.out.println( wanderer1 );

In this case, the program prints out some cryptic information about the Wanderer object. It is the class name, an @ symbol and the hexidecimal representation of the hashcode. The output looks like the following for the first Wanderer object I created.

    Wanderer@13fac

Each object created has its own hashcode that can be used to distinguish it from other objects. However, hashcodes are not very readable for most users, so there is a way for the programmer to redefine what information is printed. The information that is displayed when an object is printed using the print method is defined by an instance method named toString. Every class has a version of the toString method already defined that returns the information as described above. All classes inherit this method from the java.lang.Object class.

To redefine the toString method, you override the default version by defining a method with the same visibility and method signature as the inherited version of the method. The toString method of my Wanderer class can be overridden as follows:

    /**
     *  Returns a string representing this
     *  instance of the Wanderer class.
     */
    public String toString()
    {
        String coords = "(" + myLoc.getX() + ","
                            + myLoc.getY() + ")";

        return myName + " is at " + coords;
    }

Now, when the print or println method is used to print a Wanderer object, the new version of the toString method will be called instead of the version defined in the Object class. The String that is printed by the println method will look something like this:

    Wilma is at (11,3)

Each class can (and should!) override the toString method to return a String of characters that is more descriptive of the object than the default version provided by the Object class. This method can be called by any method that needs a String that describes the object.

The print or println methods of the PrintStream class should be adequate to produce most screen output. The only other type of output we will cover in this course is file output. Other output devices require more specialized output objects and won't be covered in this course.

File Input

As mentioned above, data can be read from a variety of different sources, including data files stored on devices such as hard disk drives and floppy drives. The file will need to be opened and a Scanner will be attached to the file object. The process is actually very similar to the console input example above. The difference is that the Scanner will be created from a File object instead of an InputStream object. This section focuses on inputting characters rather than data bytes.

The discussion and examples in this document explain the procedure when the file to be read is a text file that has valid ASCII characters to represent the data. There is one new Java I/O class to learn about:

You will also have to inform the compiler that you are calling a method that may cause a checked exception to occur. Creating a Scanner object from a File object may cause a FileNotFoundException. This is a checked exception, so be sure to catch the exception or add the throws FileNotFoundException clause to the method header. (Since FileNotFoundException is a subclass of IOException, you could put throws IOException in the method header instead of throws FileNotFoundException.) See the Java Exceptions web page for more information on handling checked exceptions.

Here's a code fragment to illustrate reading a text file:

    System.out.print( "Enter the filename: " );   // Prompt the user for a file name
    String fileName = scanner.nextLine();         // get a file name from the user
    File file = new File( fileName );             // create a File object

    if ( file.exists() )                          // check that the file exists
    {                                             // before trying to create a
                                                  // Scanner to read the file
        // Create a Scanner from the file. 
        // This statement can cause a FileNotFoundException.
        Scanner inFile = new Scanner( file );

        // For each line in the file, read in the line and display it with the line number
        int lineNum = 0;

        // Use the results of calling the hasNext method to 
        // determine if you are at the end of the file before 
        // reading the next line of the file.
        while ( inFile.hasNext() )
        {
            line = inFile.nextLine();   // read the next line

            // Output the line read to the screen for the user
            System.out.println( ++lineNum + ": " + line );
        }

        // When we're done reading the file,
        // close the Scanner object attached to the file
        inFile.close();
    }

File Input Hints

Parsing strings with split

When you are reading data into your program from a text file, you may need to interpret certain parts of each line differently. This is especially true if you need your program to create objects from text data contained in a file. Individual data items can be placed on different lines of the input data file, but this creates very long files. It is common to place all of the data items for one object on the same line and separate each item with some special character, called a delimiter. In this type of data file, each line of the file represents one record or one object. When you read in from this type of data file, you will need to read in each line of input (as a string of characters) and then divide up that string into its component pieces. This process of dividing up is called parsing. First, some definitions:

parsing
dividing a string into tokens based on the given delimiters
token
one piece of information, a "word"
delimiter
one (or more) characters used to separate tokens

Anytime you have a situation where strings contain multiple pieces of information (for example, when reading in data from a file on a line-by-line basis), then you will need to parse (i.e., divide up) the string to extract the individual pieces.

Parsing Strings in Java

Strings in Java can be parsed using the split method of the String class. ( StringTokenizer can also be used to parse a string; we won't be covering it here). This just gives a brief overview (and some examples) of some of the common (and easiest) ways to use the split method; for more detailed information see the Java API documentation for split.

Issues to consider when parsing a string:

When there is just one character used as a delimiter

Example 1

You want to divide up a phrase into words where spaces are used to separate words. For example

the music made   it   hard      to        concentrate
In this case, you have just one delimiter (space) and consecutive delimiters (i.e., several spaces in a row) should be treated as one delimiter. To parse this string in Java, you do
String phrase = "the music made   it   hard      to        concentrate";
String delims = "[ ]+";
String[] tokens = phrase.split(delims);

Note that

Example 2

Suppose each string contains an employee's last name, first name, employee ID#, and the number of hours worked for each day of the week, separated by commas. So

Smith,Katie,3014,,8.25,6.5,,,10.75,8.5
represents an employee named Katie Smith, whose ID was 3014, and who worked 8.25 hours on Monday, 6.5 hours on Tuesday, 10.75 hours on Friday, and 8.5 hours on Saturday. In this case, you have just one delimiter (comma) and consecutive delimiters (i.e., more than one comma in a row) should not be treated as one. To parse this string, you do
String employee = "Smith,Katie,3014,,8.25,6.5,,,10.75,8.5";
String delims = "[,]";
String[] tokens = employee.split(delims);

After this code executes, the tokens array will contain ten strings (note the empty strings): "Smith", "Katie", "3014", "", "8.25", "6.5", "", "", "10.75", "8.5"

There is one small wrinkle to be aware of (regardless of how consecutive delimiters are handled): if the string starts with one (or more) delimiters, then the first token will be the empty string ("").

When there are several characters being used as delimiters

Example 3

Suppose you have a string containing several English sentences that uses only commas, periods, question marks, and exclamation points as punctuation. You wish to extract the individual words in the string (excluding the punctuation). In this situation you have several delimiters (the punctuation marks as well as spaces) and you want to treat consecutive delimiters as one

String str = "This is a sentence.  This is a question, right?  Yes!  It is.";
String delims = "[ .,?!]+";
String[] tokens = str.split(delims);

All you had to do was list all the delimiter characters inside the square brackets ( [ ] ).

Example 4

Suppose you are representing arithmetic expressions using strings and wish to parse out the operands (that is, use the arithmetic operators as delimiters). The arithmetic operators that are allowed are addition (+), subtraction (-), multiplication (*), division (/), and exponentiation (^) and parentheses will not be allowed (to make it a little simpler). This situation is not as straight-forward as it might seem. There are several characters that have a special meaning when they appear inside [ ]. These characters are: ^  -  [  and two &s in a row(&&). In order to use one of these characters, we need to put \\ in front of the character:

String expr = "2*x^3 - 4/5*y + z^2";
String delims = "[+\\-*/\\^ ]+"; // so the delimiters are:  + - * / ^ space
String[] tokens = expr.split(delims);

General template for using split

String s = string_to_parse;
String delims = "[delimiters]+"; // use + to treat consecutive delims as one;
                                 // omit to treat consecutive delims separately
String[] tokens = s.split(delims);

File Output

Writing data to a file is similar to writing data to the screen. You will open a file for writing and then print to that file any data that you would like to store there. You must remember to close the file or risk having some data not be written and saved to the file. We will use of the java.io.PrintStream class for file output.

When you intend to write data to a file, you should consider what is the appropriate action to take if the file already exists. The safest option is to ask the user what to do, and then allow the user to choose overwrite the file, choose a different filename, or cancel the operation. The example shown below assumes that the file opened by the PrintStream object will be overwritten if it already exists. If you do not want to overwrite the file if it already exists, then you must create and test a File object first. The exists method of the File class will return true if the file already exists.

The nice thing about using a PrintStream object is that you are already familiar with the print and println methods that are defined for all PrintStream objects. One important thing to be aware of when doing file output using a PrintStream is that it does not do automatic line flushing. When writing information to a file, it is more efficient to wait until there is a bunch of information to write and then write it all at once than to write one piece of information to the file, then write the next piece, and so on. This process is call buffering the place where the information is stored until it gets written to the file is called the data buffer, or just buffer. When the buffer gets sufficiently full, the buffer is flushed and the information in the buffer is written to the file. If something "bad" should happen before the buffer has been flushed (for example, the program crashes), then the information in the buffer is lost and the file will not contain all the information that you may expect it to. However, even though calls to print and println won't automatically flush the buffer, we can force the buffer to flush by calling the flush method (or by closing the file using the close method). You should always flush the buffer before your code calls another method and you should always remember to close your files in order to prevent losing information.

Here's an example file output:

        // Create a PrintStream attached to a file named "out.txt".
        // This will overwrite the file if it already exists
        java.io.PrintStream ps = new java.io.PrintStream( "out.txt" );

        // Buffer some data to write to the file (doesn't actually write until flush)
        ps.print( "Some test data that will be written when flush is called.");
        
        // Flush all buffered data to the file.
        ps.flush();

        // Buffer some more data.
        ps.println( data );

        // Close the file (by closing the PrintStream).  
        // Also flushes any remaining buffered output.
        ps.close();

Conclusion

Input and output using the standard Java library of classes can be somewhat complex. By using and experimenting with each of the techniques presented here, you will be able to perform some of the most common input and output operations in your Java programs.

PlanetIO.java has examples of console based input and output and file based input and output, written by Beck Hasti.

ConsoleIO.java has additional examples of console based input and output, originally written by Jim Skrentny.

FileIO.java has an additional examples of file based input and output using using a StringTokenizer (as opposed to the split method of the String class), originally written by Jim Skrentny.

A short summary of Java I/O is also available.


Copyright © 2007-8, 2014 Beck Hasti (updates), © 2002 Deb Deppeler (original content)
Last update on 06/11/2014