More on Input file processing; introduction to output file processing;
In the previous lecture, we looked at the process of getting data from input files:
String fileName associated with text file.
FileReader fr = new FileReader (fileName);
BufferedReader inFile = new BufferedReader (fr);
line = inFile.readLine();
i = Integer.parseInt (line);
Putting all of these ideas together, we were able to construct a method that reads a list of integers from a data file.
//File: IntFiles.java
public static int readIn (String fileName, int [] list)
{
int count=0;
try
{
//The FileReader converts byte stream to char stream
FileReader fr = new FileReader (fileName);
//The BufferedReader enables efficient buffering of stream
BufferedReader inFile = new BufferedReader (fr);
String line = inFile.readLine(); //readLine() is
//in BufferedReader class
while (line != null) //null is the pointer
//that points nowhere--
//when no more lines in file,
//line = null.
{
list [count] = Integer.parseInt (line);
count++;
line = inFile.readLine();
}
inFile.close(); //not invoked if throws exception
}
catch (FileNotFoundException e)
{
System.out.println ("The file " + fileName +
" was not found.");
}
catch (IOException e)
{
}
return count;
}
We tried to read from a file and sort as a lab exercise:
Lab Exercise. Implement one of the sorting algorithms we have discussed (Bubble sort, Shell Sort, or Quick Sort) and add it to our collection of list processing routines (NumberList.java). Test it first with data input from the keyboard. Then test it on a data file on disk that you make with notepad.
Let us look at that exercise using the shell sort from the 11/27 lecture. Here is a version of NumberList with both readIn and ShellSort:
//File: NumberList.java import iostuff.*; import java.io.*; public class NumberList { public static int [] inputList () { System.out.print ("How many items in your list? "); int n=Keyboard.readInt(); System.out.println(n); //allocate n memory locations for array x int [] x = new int [n]; //fill the array x with values from the user for (int k=0; k<n; k++) { System.out.print ("Next number please: "); x [k] = Keyboard.readInt(); System.out.println(x[k]); } System.out.println(); return x; //return the filled array x } //The following method outputs to the screen an array of integers public static void display (int [] list) { for (int k=0; k<list.length; k++) { System.out.println (list[k]); } System.out.println(); } //The following method outputs to the screen a list of n integers public static void display (int [] list, int n) { for (int k=0; k<n; k++) { System.out.println (list[k]); } System.out.println(); } //SORTING ALGORITHMS //NOTE: In the following, length is an instance variable // associated with an array object. It carries the // the size of the array, NOT necessarily the number // of items input to the array. //The insertion sort resembles the process of placing cards //into a hand one at a time in order static void insertionSort (int [] list) { for (int i=1; i<list.length; i++) { //list[0], list[1], ..., list[i-1] are in order int currentItem = list[i]; int j = i-1; while (j>=0 && list[j]>currentItem) //stops when finds //a smaller item { //looking for place to put list[i] //so moving elements to the right //to make room list[j+1] = list[j]; //jth item --> j+1 slot j--; } //list[i] goes into the j+1 slot immediately to //right of smaller item list[j+1] = currentItem; } } static void swap (int [] list, int i, int j) { int temp = list[i]; list[i] = list[j]; list[j] = temp; } static void selectionSort (int [] list) { for (int k=0; k<list.length-1; k++) { int min = smallestIndex (list, k); swap (list, k, min); //swaps list[k] with list[min] } } //The following method finds the INDEX of the smallest //item from item n to the end public static int smallestIndex (int [] list, int n) { int smallIndex = n; for (int k=n+1; k<list.length; k++) { if (list[k] < list[smallIndex]) { smallIndex = k; } } return smallIndex; } //The following method finds the smallest item in a list of integers public static int smallest (int [] list) { int smallestSoFar; //The following focuses on smallestSoFar, //a variable that is compared with each item //in the list in succession. As smaller items //are encountered, they are assigned to the variable //smallestSoFar. smallestSoFar = list[0]; for (int k=1; k<list.length; k++) { if (list[k] < smallestSoFar) { smallestSoFar = list[k]; } } return smallestSoFar; } //The following two methods average an array of numbers //The following averages int's public static int average (int [] a) { int sum=0; for (int k=0; k<a.length; k++) { sum = sum + a [k]; } return sum/a.length; } //the following averages double's public static double average (double [] a) { double sum=0; for (int k=0; k<a.length; k++) { sum = sum + a [k]; } return sum/a.length; } //The following calculates the standard deviation of an array of int's public static int sd (int [] a, int average) { int sum=0; for (int k=0; k<a.length; k++) { sum = sum + (a[k]-average) * (a[k]-average); } return (int) Math.sqrt(sum/a.length); } // The next two methods implement a Shell sort private static void sortComb(int [] a, int g){ // This method sorts the subset of the array a // consisting of elements separated by the gap g int i; boolean inorder=false; while (! inorder) { inorder=true; for (i = g; i < a.length; i += g) { if (a[i-g] > a[i] ) { int temp; // exchange the out-of-order elements temp = a[i-g]; a[i-g] = a[i]; a[i] = temp; inorder = false; } } } } public static void ShellSort(int [] a ) { // This method uses sortComb to progressively bring // array a into order by sortsusing finer and finer combs // ending with an ordinary bubble sort. int gap = a.length/2; while ( gap > 0 ) { sortComb(a, gap); gap /= 2; } } //Here is the simple file reading code public static int readIn (String fileName, int [] list) { int count=0; try { //The FileReader converts byte stream to char stream FileReader fr = new FileReader (fileName); //The BufferedReader enables efficient buffering of stream BufferedReader inFile = new BufferedReader (fr); String line = inFile.readLine(); //readLine() is in //BufferedReader class while (line != null) //null is the pointer //that points nowhere -- //when no more lines in //file, line = null. { list [count] = Integer.parseInt (line); count++; line = inFile.readLine(); } inFile.close(); //not invoked if throws exception } catch (FileNotFoundException e) { System.out.println ( "The file " + fileName + " was not found."); } catch (IOException e) { } return count; } }In order to test our new code, we need a driver application:
//File: TestNumberList.java //Test of NumberList class with data from keyboard public class TestNumberList { public static void main (String [] args) { int [] number = NumberList.inputList(); System.out.println ("The list of numbers is: " ); NumberList.display(number); System.out.println ("The smallest number in the list is: " + NumberList.smallest (number)); int avg = NumberList.average (number); System.out.println ("The average of the list of numbers is: " + avg); System.out.println ("The standard deviation of the list is: " + NumberList.sd (number, avg)); NumberList.ShellSort (number); System.out.println("The sorted list is: "); NumberList.display(number); } }When we run this program, here is what we see:
>java TestNumberList How many items in your list? 5 5 Next number please: 8 8 Next number please: 7 7 Next number please: 6 6 Next number please: 5 5 Next number please: 4 4 The list of numbers is: 8 7 6 5 4 The smallest number in the list is: 4 The average of the list of numbers is: 6 The standard deviation of the list is: 1 The sorted list is: 4 5 6 7 8
Now we create a driver dprogram to test reading from a file:
//File: FileNumberList.java //Test of NumberList class with data from a file public class FileNumberList { public static void main (String [] args) { //int [] number = NumberList.inputList(); int [] number; int n; n = Integer.parseInt (args[0]); number = new int[n]; n = NumberList.readIn(args[1], number); System.out.println ("The list of numbers is: " ); NumberList.display(number); System.out.println ("The smallest number in the list is: " + NumberList.smallest (number)); int avg = NumberList.average (number); System.out.println ("The average of the list of numbers is: " + avg); System.out.println ("The standard deviation of the list is: " + NumberList.sd (number, avg)); NumberList.ShellSort (number); System.out.println("The sorted list is: "); NumberList.display(number); } }
We use an editor to create a text file named xxx with 10 numbers, one per line:
10 1 9 2 8 3 7 4 6 5
When we run it, we need to tell the program how many numbers and the file in which they are held. We use the program argument list to do this. The first argument is array element 0:
>java FileNumberList 10 xxx The list of numbers is: 10 1 9 2 8 3 7 4 6 5 The smallest number in the list is: 1 The average of the list of numbers is: 5 The standard deviation of the list is: 2 The sorted list is: 1 2 3 4 5 6 7 8 9 10
Up to this point, we have read only one number per line. In order to read more than one number per line, we will need some mechanism to breakup the line into appropriate pieces ("tokens"). We created an alternative input method for the IntFiles class that allows the input of a table of integers with exactly three columns. The methods in java.util.StringTokenizer handle breaking up the line into tokens.
//The following method requires that we
// import java.util.StringTokenizer;
public static int readInTable (String fileName, int [] [] list)
{
int row=0;
int col=0;
String s;
try
{
//The FileReader converts byte stream to char stream
FileReader fr = new FileReader (fileName);
//The BufferedReader enables efficient buffering of stream
BufferedReader inFile = new BufferedReader (fr);
String line = inFile.readLine(); //readLine() is
//in BufferedReader class
while (line != null)
{
StringTokenizer tokenizer = new StringTokenizer (line);
for (int k=0; k<3; k++)
{
s=tokenizer.nextToken(); //moves to
//next integer on the line
list [row] [k] = Integer.parseInt (s);
}
row++;
line = inFile.readLine();
}
inFile.close(); //not invoked if throws exception
}
catch (FileNotFoundException e)
{
System.out.println ("The file " + fileName
+ " was not found.");
}
catch (IOException e)
{
System.out.println (e);
}
return row;
}
Notice that we have introduced a new actor here, namely an object of the StringTokenizer class. This is necessary because each line of the file contains not just one integer, but three of them. Since line is a String object, it blurs the distinction between the three integers embedded in it. The ability to extract each of those integers is possessed by objects of the StringTokenizer class.
We modified our original TestIntegerList driver program to test this new input method on table.txt. Try it yourself.
//File: TestTable.java
import iostuff.*;
public class TestTable
{
public static void main (String [] args)
{
int [] [] table = new int [8][5];
String file = "table.txt";
int n=IntFiles.readInTable (file, table);
System.out.println ("The number of rows in the table is: " + n);
for (int row=0; row<n; row++)
{
for (int col=0; col<3; col++)
{
System.out.print (table [row] [col] + "\t");
}
System.out.println();
}
}
}
Lab Exercise. Expand the above readInTable() method to allow for a variable number of columns. I think this would require the following signature:
public static int [] readInTable (String fileName, int [] [] list)
Note that the return type of the function is now int[] rather than simply int. That's because we would like the function to tell us the number of columns as well as the number of rows. So, the concluding statements in our modified method might be:
int [] temp = new int [2];
temp [0] = row;
temp [1] = col;return temp;
HINT: Look up the countTokens() method in the StringTokenizer class.
Have fun! If you'd like to see Prof. Steinmetz's version, see the readTable() method in the updated IntFiles.java source code.
In the next lecture we'll see how to send output to a file, rather than to the screen.
PrintWriter object (converts a String to a stream of chars)
BufferedWriter object (offers staging area for char stream)
FileWriter object (converts char stream to byte stream)
file receives byte stream from FileWriter object
The corresponding steps in your Java program (in reverse order) are:
String fileName associated with text file.
FileWriter fr = new FileWriter (fileName);
BufferedWriter buffer = new BufferedWriter (fr);
PrintWriter out = new PrintWriter (buffer);
out.println (data);
out.close();
As with input, we will have to arrange to catch exceptions.