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:
Demonstrate reading data from the console.
Demonstrate reading data from text files.
Demonstrate ability to write to a text file.
Demonstrate ability to read/write multiple data types.
7.0 Audio:
7.0 Types of input
There are four ways in which input occurs:
Console: through interaction with the user at the command-line.
File: Data is read from a file.
GUI: through interaction with the user using a Graphical
User Interface (GUI). That is, a window pops up with buttons, textfields etc
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():