| CS 261 | University of Puget Sound | Spring, 2020 |
|
Computer Science II
|
||
|
Abstract Data Types and their Implementations,
Some Basic Algorithms,
Object-oriented Problem Solving, and Efficiency |
||
Warning:
This course is under development.
Although the basic structure of this course is largely established,
nothing on this Web site should be considered official or even possibly
correct.
DO NOT MAKE PLANS BASED ON THE CONTENTS OF THIS SITE UNTIL JANUARY, 2020.
This reading introduces some basics of input in Java, including input from the keyboard and from files.
Much of this reading comes from Basic Textual Input and Output in Java by Samuel Rebelsky, as part of his 2005 Java Espresso project.
In the early days of computing, programs were run only in batch mode. That is, you would start the program, wait for it to compute results (or crash), and then read the results (or error log). Initially, programmers coded any values the program would use directly into the program. Soon thereafter, however, they realized that it was far more general to place the input to a program (and the output from a program) in separate files.
With the advent of interactive computing systems, it became even more important for programs to be able to read input from a variety of sources and to send output to a variety of targets. In early interactive systems, most input was based on text that came from the keyboard and that went to a monitor or printer that showed only alphanumeric characters. Hence, the focus of early input and output commands was textual input and output.
Even with the creation of modern window-based systems, in which input can come from mice, touchscreens, and a variety of other devices and output can be graphical and auditory as well as textual, it is still useful to be able to read and write text, if only to save comments to a log and to gather data from a file.
Since text is the primitive form of information that comes from many devices, initial input is often text in many applications. When other types of input (e.g., integers or real numbers) are desired, input often involves two main steps:
In getting started with input in Java, it is useful to consider data from the terminal or from files as being a sequence of characters organized by lines. That is, input consists of a sequences of lines, and each line contains 0 or more characters. Such input is often called a stream. (As a parallel in Java, System.out is considered a stream for output.)
Since input streams are quite common for Java applications, it is hardly
surprising that several pre-defined Java classes are available for handling
input chores. For example, author, Mark Allen Weiss, suggests the use of
a Scanner class; and instructor, Samuel Rebelsky, suggests the use
of the BufferedReader and InputStreamReader classes.
Work with these two approaches is largely parallel, as shown in the
following notes.
| Using the Scanner class | Using BufferedReader and InputStreamReader |
|---|---|
| The Scanner class is discussed in Weiss's textbook and online in the Java 9 API | The use of the BufferedReader and InputStreamReader classes is discussed in Java Espresso |
To clarify how these classes might be used in an application, consider the file test.data that contains information on tests for a certain class. Each line of the file contains a student's first and last name and the results of three hour tests. Specifically, the first 19 characters in each line contain a name, the next 6 characters contain the first test score, the next 6 characters contain the second test score, and the remaining text on the line contains the third test score.
Our goal is to write a program that computes the average of the test scores for each student and the maximum and minimum scores for each test, and then prints the results in a nicely formatted table. For example, the table might have the following form:
Name Test
First Last 1 2 3 Average
Egbert Bacon 88 85 92 88.33
.
.
.
Maximum -- -- --
Minimum -- -- --
As a first approach to this task, we use the built-in classes to read a line at a time. Then, given the line, we extract substrings for the name and the various test scores, we convert the test scores to integers for computation, and then we compute the averages and maximums and minimums.
| Using the Scanner class | Using BufferedReader and InputStreamReader |
|---|---|
/* Program to compute test statistics for students
*/
package testScores;
import java.util.Scanner;
import java.io.FileReader;
import java.io.IOException;
public class TestScanner1
{
public static void main (String args[])
{ // identify name of file with test information
String testFile =
"/home/walker/public_html/courses/207.fa18/readings/test.data";
try // try needed in case opening FileReader fails
{
// set up file reader for given data file
FileReader fileReaderIn = new FileReader (testFile);
// use FileReader object to initialize scanner
Scanner fileIn = new Scanner (fileReaderIn);
// declare variables for reading and for max and min
int test1 = 0, test1max = 0, test1min = 0;
int test2 = 0, test2max = 0, test2min = 0;
int test3 = 0, test3max = 0, test3min = 0;
boolean firstTime = true;
//print headings
System.out.println (" Name Test");
System.out.println ("First Last\t\t 1 \t2 \t3 Average");
while (fileIn.hasNextLine())
{
// read entire line
String line = fileIn.nextLine();
// extract name field
String name = line.substring (0, 19);
// extract test 1 string and convert to integer
// extract character
String intString = line.substring (19, 25);
// trim leading and trailing whitespace
intString = intString.trim();
// convert to int by using an Integer static method
test1 = Integer.parseInt(intString);
// extract test 2 string and convert to integer
intString = line.substring (25, 30);
intString = intString.trim();
test2 = Integer.parseInt(intString);
// extract test 3 string and convert to integer
intString = line.substring (31).trim();
test3 = Integer.parseInt(intString);
if (firstTime)
{ // the first data read become
// initial max and min values
test1max = test1min = test1;
test2max = test2min = test2;
test3max = test3min = test3;
firstTime = false;
}
else
{
if (test1max < test1)
test1max = test1;
if (test1min > test1)
test1min = test1;
if (test2max < test2)
test2max = test2;
if (test2min > test2)
test2min = test2;
if (test3max < test3)
test3max = test3;
if (test3min > test3)
test3min = test3;
}
// compute average and print results for line
double avg = (test1 + test2 + test3) / 3.0;
System.out.println (name + "\t" + test1
+ "\t" + test2
+ "\t" + test3
+ "\t" + avg);
}
// print concluding maximums and minimums
System.out.println ("\nMaximum \t\t" + test1max
+ "\t" + test2max
+ "\t" + test3max);
System.out.println ("Minimum \t\t" + test1min
+ "\t" + test2min
+ "\t" + test3min);
}
catch (IOException e)
{ // identify any error that arises
System.err.println (e);
}
}
}
|
/* Program to compute test statistics for students
*/
package testScores;
import java.io.File;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;
public class TestBufferedReader1
{
public static void main (String args[])
{ // identify name of file with test information
String testFile =
"/home/walker/public_html/courses/207.fa18/readings/test.data";
try // try needed in case opening File fails
{
// set up file reader for given data file
FileReader istream = new FileReader (testFile);
// use FileReader object to initialize scanner
BufferedReader fileIn = new BufferedReader (istream);
// declare variables for reading and for max and min
int test1 = 0, test1max = 0, test1min = 0;
int test2 = 0, test2max = 0, test2min = 0;
int test3 = 0, test3max = 0, test3min = 0;
boolean firstTime = true;
//print headings
System.out.println (" Name Test");
System.out.println ("First Last \t\t 1\t 2\t 3 Average");
// read entire first line
String line = fileIn.readLine();
while (line != null)
{
// extract name field
String name = line.substring (0, 19);
// extract test 1 string and convert to integer
// extract character
String intString = line.substring (19, 25);
// trim leading and trailing whitespace
intString = intString.trim();
// convert to int using an Integer static method
test1 = Integer.parseInt(intString);
// extract test 2 string and convert to integer
intString = line.substring (25, 30);
intString = intString.trim();
test2 = Integer.parseInt(intString);
// extract test 3 string and convert to integer
intString = line.substring (31).trim();
test3 = Integer.parseInt(intString);
if (firstTime)
{ // the first data read become
// initial max and min values
test1max = test1min = test1;
test2max = test2min = test2;
test3max = test3min = test3;
firstTime = false;
}
else
{
if (test1max < test1)
test1max = test1;
if (test1min > test1)
test1min = test1;
if (test2max < test2)
test2max = test2;
if (test2min > test2)
test2min = test2;
if (test3max < test3)
test3max = test3;
if (test3min > test3)
test3min = test3;
}
// compute average and print results for line
double avg = (test1 + test2 + test3) / 3.0;
System.out.println (name + "\t" + test1
+ "\t" + test2
+ "\t" + test3
+ "\t" + avg);
// read entire next line to prepare for next loop iteration
line = fileIn.readLine();
}
// print concluding maximums and minimums
System.out.println ("\nMaximum \t\t" + test1max
+ "\t" + test2max
+ "\t" + test3max);
System.out.println ("Minimum \t\t" + test1min
+ "\t" + test2min
+ "\t" + test3min);
}
catch (IOException e)
{ // identify any error that arises
System.err.println (e);
}
}
}
|
Instead of reading from a file, both approaches allow System.in to be used as an input stream in place of the FileReader in these examples. Also, since System.in is always opened when the program is opened, no try..catch block is needed when using the Scanner class.
After making the relevant changes, the first part of each program could be adjusted as follows:
| Using the Scanner class | Using BufferedReader and InputStreamReader |
|---|---|
import java.util.Scanner;
public class TestScanner2
{
public static void main (String args[])
{ // use System.in to initialize scanner
Scanner fileIn = new Scanner (System.in);
|
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;
public class TestBufferedReader2
{
public static void main (String args[])
{
try // try needed in case opening the input stream fails
{
// create new input stream
InputStreamReader istream = new InputStreamReader (System.in);
// use FileReader object to initialize scanner
BufferedReader fileIn = new BufferedReader (istream);
|
| The full program for keyboard input with the Scanner class is available as TestScanner2.java | The full program for keyboard input with the BufferedReader class is available as TestBufferedReader2.java |
Note "End of Keyboard Input": When reading from the input in Eclipse in a Linux environment, use "control-d" to indicate the end of input (equivalent to an "end of file" when reading from a file.
Both the Scanner and BufferedReader class have some additional capabilities, including the following.
| Using the Scanner class | Using BufferedReader and InputStreamReader |
|---|---|
| The Scanner class allows reading of several primitive types (e.g., int, double) as well as strings. | the BufferedReader class allows rewinding of input, so parts of the same input can be read again. |
|
The Scanner allows reading of various primitive types. Scanner divides the input into units or tokens. A program then can test the type of the next token and read the token as a given type. Some useful capabilities are:
Details are given in the Java documentation for the Scanner class |
Rewinding Input (from Espresso: A Concentrated Introduction to Java by Samuel Rebelsky)
One nice part about |
| Program TestScanner3.java shows how these Scanner methods might be used to read the file of names and test scores. |
Example:
fileIn.mark(1024);
System.out.println ("fileIn.readLine());
System.out.println ("fileIn.readLine());
fileIn.reset();
|
|
created 2 May 2000 by Henry M. Walker revised 27 January 2012 EOF for keyboard input added 12 February 2013 |
|
| For more information, please contact Henry M. Walker at walker@cs.grinnell.edu. |