Java Input and Output (I/O)


Contents


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 JOptionPane or an InputBox to accept information from the user.  You are certainly familiar with programs that are controlled simply by clicking a mouse button when the mouse's cursor is in a specific area of the screen, and via pen input devices.  Still other programs, like word processing programs, get some of their input from a file that is stored on one of the computer's hard drives, or an external device such as a USB drive.  Some programs, like web browsers, get their data from the Internet via 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 imagination and skills.

Throughout the semester, we will be performing input and output through the use of several of the classes in the Java Standard Edition API (currently JDK 8). We will limit our discussion to only a few classes and forms of I/O for simplicity.  You may wonder why there are so many standard Java classes for input and output.  The answer is flexibility.  Standard Java classes 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 some increased complexity.

Regarding user input error handling:

In general, if a user enters letters when a program is expecting numbers, an exception [error] will occur.  Such exceptions must be understood and handled by the programmer so that the program will not crash due to a simple typing error.  However, there are times when that type of user input validation is not the core focus of our assignment.  In those cases, we will not necessarily specify exactly what error message is to be displayed for each of the many types of errors.  If we don't state the error message, it likely that is not a case we intend to test.  Ask if you are unsure.

Students are asked not to change prompts or output formats unless directed by the assignment.  In our time of large scale program grading, we must make use of programs to compile and run your code via test suites and other automated tools.  For such programs to recognize a correct answer, the output produced by your program must match exactly the sequence and format of output we are expecting.  We typically provide samples runs to ensure that you know exactly what we are expecting from your program.

Console Output

The console window is the window panel that is automatically brought to the focus when you run a program that displays output from within Eclipse.  Most programming languages have the ability to display a string of characters to this window on the screen or to some other standard display device. 

We call this console output because the string of characters is sent out (from your program) and it appears in a console window.  The System.out object is an instance of the PrintStream class, which is a type of Stream and it is this class that we will use to display standard output while the program is running.  This is an important output option, since many programs that we write will produce text output to be used as input to another program.  There is very little to know to use this form of output in Java.  Just concatenate the values and strings you wish to display to the user.  The System class is part of the java.lang package and does not need to be imported.  Here is an example of sending output to the console window.

for ( int i = 0; i < 10 ; i++ )
   System.out.println("The cube i^3 of " + i + " is " + (int)(Math.pow(i,2)) );

Another common use for console output is to display a prompt the user for input.  Leave a space after the prompt if you chose to have the user enter their answer on the same line as the prompt (as this example demonstrate).  Here is an example of prompting the user. The next section will describe user input options.

   // Prompt the user for some type of information
   System.out.print( "What is your name? " );

   // code to read (scan and save) user input would be here

An alternative output technique uses graphic user interface (GUI) objects to display text and other graphic output.  The design and coding of GUI is beyond the scope of this document. 

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 the 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 will describe 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 displayed to the console 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 wanderer = new Wanderer( "Wilma", Color.orange );
    System.out.println( wanderer );

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 Wanderer object created.

    Wanderer@13fac

Each object created (instantiated or constructed) 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 or override what information is printed when an object reference is sent to the print or println method. 

The information that is displayed when an object is printed using the print method is defined by an instance method named toString().  Every class already has a toString method already defined that returns the information as described above.  All classes inherit the toString 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 the Wanderer class can be overridden as follows:

    /**
     *  Returns a string representing this instance of the Wanderer class.
     *  Example: Wilma is at (3,4) 
     */
    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 System.out.println(wanderer) method call will look something like this:

    Wilma is at (11,3)

Each Java 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 you need.  Another type of output we will cover in this course is file output.  Other output types require more specialized output objects and won't be covered in this course.

Streams

A Stream object is used to store information needed to connect a computer program to an input or output device.  There is a Reader object that adds functionality to input streams and a Printer object that adds functionality to output streams.  The PrintStream class extends the Printer 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, etc.

Because Streams can be tedious and error prone to use.  The Standard Edition of Java now contains two classes to make reading input streams and sending output to output streams even more convenient.  We will use java.util.Scanner for reading characters typed by the user on the keyboard, and we will use java.io.PrintWriter to write text information produces by our program to a file on the hard drive or other external data storage.

Console (Keyboard) Input

Programs that require the user to input information while the program is running, must prompt the user for that information in some manner. Note: The user will only know what information to type, if the program prompts (asks for) and describes the information that is required.  (See Console Output for more information on output and an example user prompt.)

After the prompt is displayed, the program will wait for the user to finish typing and press Enter. 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. Console input is string of characters that are entered by typing on the keyboard while the program is running and waiting for user input. Whatever the user typed is saved in an input stream and is available to the program by request in the form of a String object.  We may also learn and use specialized methods to parse (interpret) the string of characters as an int or a double value.

Ever since Java 5, keyboard input and user input in general has been much better for the begining programmer.  Where it used to require the use of several of the Java I/O classes, we now can focus on one type (and a few exception classes).

java.util.Scanner - connects program to an input stream and provides functionality (methods) to return data from the input stream in the form of text strings, int values, and double values.

We will use the System.in object to create an instance of the Scanner class and then use that scanner object to get the user's typed input.

Steps for console based user input:

  1. Construct a Scanner object connected to the standard input stream, System.in
    There must be only one Scanner connected to System.in, or input to your program may not be read in the order it was typed. Place your scanner at start of main method and pass it to other methods as needed or declare it to be a static data member.
  2. Get user input
    1. Display a prompt to the user for the desired data.
    2. Check to see if the scanner has more data.
    3. If STDIN.hasNextLine() returns true, use STDIN.nextLine() to get the next whole line of text from the user and assign that value to a variable to save it for use in your program.
  3. If STDIN is constructed within the main method (not a class data field), call STDIN.close() to close the input stream when the program ends.

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

    // In a method somewhere...
    // 1. Create an class member in your main program class
    Scanner stdin = new Scanner( System.in );

    // 2. Prompt the user
    System.out.print( "What is your name? " );

    // 3. Use the Scanner to get a line of text from the user.
    String name = stdin.nextLine();

    // 4. Now, you can do anything with the input string that you need to.
    // Like, output it to the user.
    System.out.println( "Hi " + name + "! Welcome to my Super Duper Program" );
    // 5. Once, you are done reading ALL input, close the Scanner
    stdin.close();

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

Did you import the java.util.Scanner class?  The Scanner (and other I/O classes) is not in the standard java.lang package.  You must import Scanner from the java.util package.

    import java.util.*;  // needed for Scanner, Random, ArrayList, etc

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

        // Program execution starts here
        public static void main ( String [] args ) {

            // Prompt the user
            System.out.print( "What is your name? " );

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

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

        } // 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 is 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 or learn to use the nextInt method if you wish to store it in an int variable or data member.  Here's how:

  1. Get a String of characters that is in an integer format, eg.  "123".
    String input = stdin.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.

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

 

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 the standard 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.  Here are two new Java I/O classes to review:

Here's a code fragment to illustrate reading a text file. Creating a Scanner connected to a file may cause an IOException which is a checked exception, so be sure to catch the exception or add the throws IOException clause to the method header.  See the Java Exceptions web page for more information on handling checked exceptions.

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

    if ( file.exists() )                          // check that the file exists
    {                                             // before trying to create a
                                                  // BufferedReader
        // Create a Scanner from the file
        java.util.Scanner inFile = new java.util.Scanner( file );

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

        // Compare the results of calling the readLine method to null
        // to determine if you are at the end of the file.
        while ( inFile.hasNextLine() )
        {
            String line = inFile.nextLine(); // save if needed 
            System.out.println( ++lineNum + ": " + line);
        }

        // Close the buffered reader input stream attached to the file
        inFile.close();
    }

File Input Hints

Tokenizing a String (split into parts -- a.k.a "tokens")

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 much more 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.  The example data file "student_scores.txt" shown below, contains data for three students and three exams scores for each student.

Screen Shot of student_scores.txt

Each line of input is interpreted as a string of characters for the name, that is followed by three integers for each object created.  The delimiter character is the ':' in the above data file.

The process of splitting a line of text into different parts is known as tokenizing, and each piece is a token.  The standard Java library class String includes a method called, split that makes this process convenient for Java programmers.  Without this method, you would need to use nested repetition and selection statements to process each character one at a time and determine if it is part of the name or one of the exam scores and then store it accordingly.  Java programmers simply need to learn how to use the split method and what the array of String values that is returned will contain.  Refer to the String javadoc for more detailed information on methods other than those presented here.

An array of String tokens is created from a String object by using the split method to create the array.  Once you have the array, use the length field to find out how many tokens exist in that array.  There is another class that can also be used to split a String into tokens. The StringTokenizer class is in the java.util package.  It allows you to read and process one token at a time instead of getting an array of all tokens.   

Here is a code fragment that reads the file shown above and computes the average score for each student listed.

        // Make sure that the file student_scores.txt exists and has 
        // valid data records.  Otherwise, exceptions will occur.
        File gradeFile = new File( "student_scores.txt" );
        if ( gradeFile.exists() )
        {
            // Create the buffered reader for reading the file
            Scanner inFile = new Scanner( new File( gradeFile ) );

            String line = null;  // no line read yet

            // If line is not end of file continue
            while ( inFile.hasNextLine() ) 
            {
                // Read next line of the file
                line = inFile.nextLine();

                // Create a StringTokenizer with a colon sign as a delimiter
                String[] token = line.split(":" );
                String name = token[0];
  
                // Display the content of the first token
                System.out.print( "   Name: " + token[0] );

                // Display the total number of tokens remaining this string
                int numScores = token.length-1;  // the name is the first token
            
                // Initialize the sum to zero
                int sum = 0;

                // Get each score, add it to the sum and print it
                for ( int i=1; i <= numScores; i++ )
                {
                    int score = Integer.parseInt( token[i] );
                    sum += score;
                }

                // Display the average score for this student
                System.out.println( " average = " + sum/numScores );  

            } // end while not at end of file
            
            // Close the Scanner
            inFile.close();
            
        } // end if the grade file doesn't exist

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 each of these classes.

When you intend to write data to a file, you should consider what the appropriate action to take is, 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.   However, we typically take the easiest way and simply overwrite the file without warning to the user. 

The example shown below assumes that the file opened by the PrintWriter 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.

    
        // Create a PrintWriter that automatically flushes data
        // to the output file whenever the println method is used.
        java.io.PrintWriter pw = new java.io.PrintWriter( "out.txt", true );

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

        // Write some data and automatically flush it to the file.
        pw.println( data );

        // Close the PrintWriter for added safety.
        pw.close();

The nice thing about using a PrintWriter object is that you are already familiar with the print and println methods that are defined for all PrintWriter objects.  By choosing the constructor that accepts a String for the filename and a boolean value, we are able to set the PrintWriter object so that it will always flush the data buffer on all calls to println.  This is safe, but less efficient.  It is more efficient to wait until the buffer is full before writing to disk.  In that case, the flush method must be called or the file must be closed to flush the remaining data from the buffer.

Conclusion

Input and output using the standard Java library of classes is quite manageable once you learn to use Java's Scanner and PrintWriter classes connected to files.  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.

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

FileEcho.java has examples of file based input, written by Deb Deppeler.
FileIO.java has an additional examples of file based input and output, written by Jim Skrentny.


Copyright © 2003,2016 Deb Deppeler.  (deppeler@cs.wisc.edu)
Last update on 9/27/2016

Notes:

  1. Example

Here is a program that tries to open a file for reading. The name of the file is given by the first command-line argument .

public class Test {
    public static void main(String[] args) {
        Scanner fileIn;
        File inputFile;    
        try {
            inputFile = new File(args[0]);
            fileIn =   new Scanner(inputFile);  // may throw FileNotFoundException
            while ( fileIn.hasNext() ) {
                 System.out.println( fileIn.nextLine() );
            }
        } catch (FileNotFoundException ex) {
            System.out.println("file " + args[0] + " not found");
        } catch (Exception ex) {
            System.out.println("unable to read file contents");
            System.out.println(ex.getMessage());
        } finally {
            System.out.println("done");
        }
    }
}

Notes:

  1. The program really should make sure there is a command-line argument before attempting to use args[0].
  2. Also, it probably makes more sense to put the try block in a loop, so that if the file is not found the user can be asked to enter a new file name and a new attempt to open the file can be made.
  3. As is, if the user runs the program with a bad file name foo, the message "file foo not found" will be printed and the program will halt.
  4. If there were no try block and the program were run with a bad file name foo, a more complicated message, something like this:
    java.io.FilenotFoundException: foo
        at java.io.FileInputStream ...
        at ...
        at Test.main ...
    	 
    would be printed. (Actually, if there were no try/catch for the FileNotFoundException, the program wouldn't compile because it fails to list that exception as one that might be thrown. )