Module 7: Input / Output


Objectives

 

Most programs interact with what's outside the program: either directly with users or with files. We need to learn how this is done.

By the end of this module, you will be able to:

 

7.0 Audio:
 


7.0    Types of input

 

There are four ways in which input occurs:

  1. Console: through interaction with the user at the command-line.

  2. File: Data is read from a file.

  3. GUI: through interaction with the user using a Graphical User Interface (GUI). That is, a window pops up with buttons, textfields etc

  4. Program-to-program communication: There are many ways a program can communicate directly with another program, including across the internet.

In this unit, we will cover only the first two.
 


7.1    Console input

 

We have already used IOTool to read from the console (terminal):

     String s = IOTool.readStringFromTerminal ("Enter a string: ");
     System.out.println ("You typed: " + s);

     int k = IOTool.readIntFromTerminal ("Enter an integer: ");
     System.out.println ("You typed: " + k);
     

IOTool was developed for this course to hide some of the detail.

We will now peek into some of this detail because a similar approach will work for reading from files.
 

Here is a program that reads a single integer from the console:

 

7.1 Exercise: Try out the above program. What happens if you were to hit enter instead of typing in an integer? What happens when you type a char or double instead? What if your integer is too big?
 

Let's point out a few things:

  • For simplicity of exposition, we have not designed our program to handle mis-typed input. Real applications must of course handle these issues.

  • The Scanner class is a library class in the java.util library included in the language:

  • Here, we used our variable name console:

    We could have called our variable anything, like x or commandlineWindow.

  • We have written a "prompt" to the commandline window.

    Notice: the use of print instead of println.

 

7.2 Exercise: What happens when you use println instead of print? Is it possible not to print a prompt at all? Try it.
 

  • We used the nextInt method to get the integer that got typed in.

  • This results in the value being stored in our variable i.

  • Notice that these methods are similar to the kinds of "object" methods for String variables:
        String s = "Hello World!";
        int k = s.length ();
        char c = s.charAt (k-1);
        String s = s.substring (0,5);
        
 

Let's now write code to input multiple integers on a single line:

And to acquire an int and a double:

 

7.3 Exercise: What happens if you type in two int's?
 

Next, a string:

  • Notice that, in the output, we enclose the string in brackets.
           ⇒ This is so that it's clear what's in the string.
 

7.4 Exercise: Type in a string with spaces on either side and in the middle, and see what happens.
 

7.5 Audio:
 


7.2    Applying Scanner to strings

 

Sometimes, instead of separately reading multiple integers or other things from the screen, it's more useful to just read a line of text (which could contain the integers) and work on extracting the integers from the string (the line of text).

The Scanner class can be applied to strings:

  • Notice how the Scanner is applied to the string s.

  • We changed our variable name to stringScanner, just for clarity.

  • Note: both numbers were extracted from the string s.
 

Thus, as an alternative to reading two numbers from the console, we could have written:

 

7.6 Exercise: In MyScannerExample.java modify the above to read three real numbers. First read in a string and extract the three numbers from the string.
 


7.3    Reading from a file

 

We'll start by reading a single integer from a file:

  • Suppose we have a file called file1.data with the following contents:
    25
        

  • Thus, there's a single integer on a line.

  • Here's the program:

  • Let's point out a few things.

  • First, we need an additional import statement to be able to use the File class:

    This is from Java's I/O (input-output) library.

  • Next, we're seeing for the first time a new construct, the try-catch clause:

  • How does this work and why is it needed?
    We will not cover Java's exceptions in any great detail, but will point out a few things:
    • An exception occurs when something goes wrong.
             ⇒ In this case, the file perhaps does not exist.
    • It is possible to write code that throws exceptions when something goes wrong (using the throw reserved word).
    • If you call a method that can throw an exception, then you must be able to catch it.
             ⇒ Using a try-catch clause.
    • If all goes well the "good" code in the try part executes.
    • If something goes wrong, and an exception is thrown, then execution continues in the catch clause:

    • It is customary to do something useful in the catch clause:

  • In this unit, we will not focus on exceptions, and will merely use the try-catch because we have to.

  • In a real application, we would have plenty of code in the catch part to deal with errors gracefully.

  • Notice that the same Scanner class is being used differently, now with a File:

  • Once a Scanner has been "attached" to the file, reading int's is the same as before:

 

Next, let's read multiple integers:

  • Suppose our file has multiple integers, one per line:
    1
    4
    9
    16
    25
        

  • We will assume that we don't know ahead of time how many lines are in the file.

  • Here's the program:

  • First, we use a while loop because we don't know how many lines the file has:

  • We use the hasNextInt method (which returns true or false) depending on whether or not the file has more integer's remaining to be read:

  • As long as there are more integers, a call to nextInt method will extract the next one.

  • When there are no more integers, hasNextInt returns false and execution goes past the while-loop.
 

7.7 Exercise: In MyFileExample.java modify the above to read the numbers and print out their sum. Note: you'll need to create the data in a file called file1.data using pico.
 

7.8 Video:

 


7.4    Reading from a file - more examples

 

Let's now read a bunch of (x,y) coordinates from a file.

  • Suppose our data looks like this:
    5
    1.0   1.0
    2.0   4.0
    3.0   9.0
    4.0   16.0
    5.0   25.0
        
    Here, the first line has an integer that tells us how many (x,y) pairs are in the rest of the file.

  • What we'd like to do: read the points into double arrays x and y.

  • Here's the program:

  • Notice that we read the single integer first:

    This let's us create the arrays with the right size.

  • Once we've created the arrays, we can use a for loop because we know exactly how many points there are:

 

7.9 Exercise: What happens if there are more than 5 points in the file but the first line still has 5? What if the first line has 5, but there are fewer than 5 points in the file?
 

7.10 Exercise: In MyFileExample2.java rewrite the above using a while-loop instead of a for-loop.
 

Next, let's consider the case where we don't know how many points are in the file:

  • Suppose our data looks like this:
    1.0   1.0
    2.0   4.0
    3.0   9.0
    4.0   16.0
    5.0   25.0
        

  • If we don't know how many points there are, how will we create the arrays (whose sizes need to be known)?

  • What we need to do: first count how many lines, then make the arrays, and then read the lines again for the data.

  • Here's the program:

  • Notice that we first read line-by-line (just as strings, without looking for numbers), just to count the number of lines:

  • Once we know how many points, we can size the array:

  • After which, we read the points into the arrays.

  • To start again, we "re-create" the Scanner but using the same variable:

 

Let's examine one more way to read the points:

  • We'll read lines as strings, and then use a String scanner.

  • Here's the idea:
        1.  Count the number of lines, n
        2.  Make the arrays of size n
        3.  In a for or while loop {
        4.      Read a line as a string
        5.      Extract the numbers from the string
        6.      Put the numbers in the array.
        7.  }
        

  • Here's the program (showing the code in the try clause):

  • Notice that we use a fresh new scanner for each string that is read line-by-line:

  • When do we do this, as opposed to read numbers directly?
           ⇒ When each line could possibly be different, or have different data.
 

7.11 Exercise: Add a println inside both while-loops to print the strings, writing in MyFileExample3.java.
 

7.12 Exercise: In MyFileExample4.java re-write the second while-loop as a for-loop.
 

7.13 Audio:
 


7.5    Writing to a file

 

To demonstrate writing, let's read from one file and write to another, in effect, make a copy of the first file.

  • Let's say we have a file called file3.data (the above set of points), for example.

  • We want to make a copy of this file and call it file4.data.

  • Here's the program:

  • For output to a file, we use the PrintWriter class together with a File class:

  • This peculiar syntax will make sense only after understanding how Java objects work (in a later course).

  • One minor tweak to remember: we need to close the output file when the writing is done:

    Otherwise the file does not get written out.

 

Let's now add code to take the filenames from the commandline.

Before that let's review how commandline arguments work:

  • Consider this program:

 

7.14 Exercise: Run the program - what is the output?
 

7.15 Exercise: Now run the program with some commandline arguments such as:

    java CommandLineArguments hello world!
    
What is the output? Try more strings after CommandLineArguments.
 

File copy via commandline arguments:

  • What we'd like to do is imitate file copying on Unix at the commandline:
        java Copy file3.data file4.data
        
    This should copy from file3.data into a new file called file4.data.

  • We have already written the copying part.

  • All that's left is extracting the names from the commandline
           ⇒ We've seen how to do this from argv.

  • Here is the program:

  • Notice that we expect the "from" file's name to be in argv[0] and the "to" file's name in argv[1].

  • Of course, the user may not type in the correct number of arguments
           ⇒ This is why we check that there are exactly two arguments.
 

7.16 Exercise: Try it with the wrong number of arguments. What gets printed out?
 


7.6    printf

 

Java's println is useful but not very good with controlling the number of digits of accuracy.

As as example, consider this program:

	double avg1 = (1.1 + 2.2 + 3.3) / 3;    // Should be 2.2.
	double avg2 = (3.06 + 3.08) / 2.0;      // Should be 3.07

	// Using println:
	System.out.println ("avg1=" + avg1 + " avg2=" + avg2);

	// Using printf:
	System.out.printf ("avg1=%4.2f avg2=%4.2f\n", avg1, avg2);
     
The output from println exemplifies the kind of round-off error typical in computing with real numbers:
avg1=2.1999999999999997 avg2=3.0700000000000003
     

To mitigate the "ugliness" of this kind of output, we'd like to control the number of digits after the decimal point.
 

Using printf:

  • The printf() method allows one to do this.

  • However, it's a bit strange to use.

  • The printf() method uses a formatting specification encoded in a string. This string needs to be the first argument to printf():
    	System.out.printf ("avg1=%4.2f avg2=%4.2f\n", avg1, avg2);
         

  • The actual variables to be printed follow the format string:
    	System.out.printf ("avg1=%4.2f avg2=%4.2f\n", avg1, avg2);
         

  • To each variable that needs printing, we must have a corresponding part of the format string that begins with the percent (%) symbol.

  • Let's decode one of these:
    	System.out.printf ("avg1=%4.2f avg2=%4.2f\n", avg1, avg2);
         
    • The %4.2f is saying "4 digits total with 2 digits after the decimal, and it's a floating point number".
    • Also the first %-format applies to the first variable that follows (in this case: avg1).
    • We could have opted for more digits by writing %10.7f for example (10 digits total, with 7 after the decimal point).
    • printf then figures out what to do.
    • Think of printf as printing the formatting string but substituting actual numbers in place of the the percent-format specifications.
    • Thus, the second %-format applies to the second variable:
      	System.out.printf ("avg1=%4.2f avg2=%4.2f\n", avg1, avg2);
           
      and so on.

  • Notice that we need to explicitly include the \n to end the line.

  • Such is the strangeness of printf.

  • It is, however, very useful in cleaning up output.
 

7.17 Audio:




On to Module 8



© 2017, Rahul Simha