Readingfileswithloops

advertisement
File Input/output using Loops
Frequently a program will require more input data than can simply be input by a user at the keyboard. Data
files can be prepared ahead of time using a text editor, stored on disk, and accessed via an executing
program. Also, instead of writing output to the screen, a program can direct that that output be stored in a file
and saved to disk.
There are many classes provided by Java that help us read from & write to files. The simplest are classes
Scanner and PrintWriter.
Before we cover these classes in detail, we need to review some terms and concepts involved with files:

Binary and Text Files: A binary file stores data in the format that it is stored in memory, in an
internal format. A text file stores data as ASCII values, in a human readable format. When data is
stored in binary format it does not need to be translated to or from ASCII and therefore data transfer
is more efficient and optimized.

Stream I/O: This refers to the manner in which data is stored in ( or output to) a file. With stream
I/O data is read as a series of continuous characters or bytes. This is how input from the keyboard is
read. Two classes FileInputStream and FileOutputStream are used to access streams of bytes.
Classes Reader and Writer and their descendents (FileReader and PrintWriter) are used to access
streams of characters. We will learn to use class PrintWriter to write data to an output file, and class
FileReader to allow Scanner to read input from a file.

Buffered Stream: rather than read one character/byte at a time from the input stream (or write one
character/byte at a time to the output stream), we can create a “buffered stream” in memory
whereby a “block” of stream data is written to (or read from) the buffer, before any actual access to
the input/output device occurs. We can think of the buffer, as a container in memory into which our
data is written. When the buffer is full, it’s contents are written to the device. This allows multiple
reads/writes to occur from the buffer, between actual accesses to the device, thus speeding up the
process of I/O again.
Reading input from a File
To read data from a file, the programmer needs to have an understanding of the format of the data stored in
the file, and its meaning. Often each physical line will contain multiple values which together form a logical
record. A logical record is a set of values which together describe one unique entity in our problem space.
For example if we have a data file containing information about employees and their hours worked it might
look like the following:
Smith John 37.5 7.35 s b
Lewis Larry 45.0 5.50 s n
Jones James 55.0 8.20 m b
In this example, the first string represents the employee’s last name, followed by first name, number of
hours worked, hourly wage, whether single or married, and whether or not they are benefits eligible.
So the first line would translate into:
John Smith, who worked 37.5 hours, at $7.35 per hour, single, and is benefits eligible.
We would write our program to read and process the data one line at a time.
Class Scanner offers many methods that you can use with loops to read multiple “lines” of data from a data
file. In addition to the methods that accomplish input, nextInt(), nextFloat() etcetera that would be used to
access individual values, Class Scanner offers others that manipulate and test the contents of a file so that we
do not attempt to read beyond the end of the physical file, these include:
o hasNext(): This method returns true if the data file has more data of any type that has not yet been
read.
o hasNextInt(): returns true if the next value in the data file can be interpreted as an Integer.
o hasNexttFloat(): returns true if the next value in the data file can be interpreted as an floating point
number.
o hasNextBoolean(): returns true if the next value in the data file can be interpreted as a Boolean value.
o hasNextLine(): returns true if there is another line of input in the file.
Using one of these methods, as we can create a loop to read data from a file, until all of that data is
exhausted.
For example, if we have defined a Scanner instance, called console the logic of our program would look like:
while (console.hasNext()) {
//READ THE DATA FROM THAT LINE
// PROCESS THE DATA
}
We could also use the method hasNextLine()
To allow Scanner to access a physical file, we must use class FileReader. Instances of this class are used to
create a connection between out program and a physical file:
Scanner infile = new Scanner(new FileReader(“c:\\mydata.txt”);
Our
Program
mydata.txt
Any methods from Scanner that are invoked for “infile” are now applied to the data file, rather than the
console. In the previous example the instance of FileReader is created when we create the instance of
scanner, there are other ways:
FileReader name = new FileReader(“path and file name”);
We can define instance of FileReader separately, the filename given may or may not include the full path, if
only a file name is given ie: “mydata.txt” then the file is assumed to be in the current working directory.
You will notice something unusual in the first example which included a path name. The character \ is a
control character in Java, as in \n which is the new line character. If it is part of a path name, then we must
use two \\. So for example: “c:\\cs110\\inputdata\\mydata.txt”.
Once the instance of FileReader is declared, we can then use it in the declaration of our scanner:
FileReader inputFile = new FileReader( “mydata.txt”);
Scanner infile = new Scanner(inputFile);
Please Note: when declaring an instance of FileReader, the file name can also be specified using a string
variable, instead of a quoted literal. Which means it is possible to prompt the user for the name of the input
file, read it into a string variable, and then create our connection to the file.
String filename;
Scanner console = new Scanner(System.in);
System.out.println(“Please enter the name of the file to be read. “);
filename = console.nextLine();
FileReader inputFile = new FileReader(filename);
Scanner input = new Scanner(inputFile);
There is a possible error condition for which we must account in case the file we are accessing does not exist.
This is a “file not found” exception, and this causes Java to raise or “throw” an IOException. What does
that mean anyway????
There are two types of exceptions thrown by Java methods: checked and unchecked. An exception is an
error that occurs during the execution of a program.. When you call a method that throws a “checked”
exception, the compiler checks to see that you don’t ignore it!!!!!!! “Checked” exceptions are caused by
external circumstances that the programmer can not control or prevent. Therefore your program must
provide a means of recognizing that these can occur and respond to them. Class FileReader throws checked
exceptions. An unchecked exception typically arises from a mistake made by the programmer such as trying
to read past the end of a string. The compiler does not check for these types of errors.
We can write exception handlers which are special sections of code that are invoked when the error occurs,
or we can choose to simply pass the error “back”, calling routine, which in this case to the operating system.
We do this through using the “throws” specifier in our method heading for method main.
import java.io.*;
public class readingFiles1 {
public static void main(String[] args) throws IOException {
File infile = new File("c:\\cs110\\java\\indat.txt");
FileReader in = new FileReader(infile);
}
}
If the file doesn’t exit this displays:
Exception in thread "main" java.io.FileNotFoundException:
c:\cs110\java\indat.txt (The system cannot find the file specified)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(Unknown Source)
at java.io.FileReader.<init>(Unknown Source)
at readingFiles1.main(readingFiles1.java:7)
The “throws” specifier just indicates that you KNOW that this exception might occur, and to
terminate your method when this happens, passing the exception back to the CALLING program.
The caller then needs to make the same decision – either handle the exception or pass it back to it’s
calling program.
Example of reading an input file;
Write a program to read employee information from a data file, and calculate the employee’s weekly pay and
withholdings using the following formula:
grossPay = hours worked * hourly rate
Tax = grossPay * taxRate
If employee is married, taxRate = 17%, if single 13%
If the employee is benefits eligible,
benefitsCost = grossPay * 3%.
netPay = grossPay –(benefitsCost + tax);
// the format of the data file is lastname firstname hoursWorked Rate taxStatus BenefitsEligible
import java.util.*;
import java.io.*;
public class payCheck {
public static void main(String[] args) throws IOException {
final float SINGLERATE = .13f;
final float MARRIEDRATE = .17f;
final float BENEFITSRATE = .03f;
String last, first;
char benefits, taxCode;
float hoursWorked, rate, netPay, grossPay, tax=0,
benefitsCost, taxRate;
FileReader inputFile = new FileReader("employee.txt");
Scanner input = new Scanner(inputFile);
System.out.printf("%-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s\n", "Last",
"First", "Hours", "Pay", "Tax", "Benefits", "Gross", "Net");
System.out.printf("%-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s\n\n","Name", "Name",
"Worked", "Rate", "Cost", "Cost", "Pay", "Pay");
while (input.hasNextLine()) {
last = input.next();
first = input.next();
hoursWorked = input.nextFloat();
rate = input.nextFloat();
taxCode = (input.next()).charAt(0);
benefits = (input.next()).charAt(0);
grossPay = hoursWorked * rate;
if (taxCode == 's' || taxCode == 'S') tax = grossPay *SINGLERATE;
else if (taxCode == 'm' || taxCode == 'M')
tax = grossPay * MARRIEDRATE;
else System.out.println("INVALID TAXCODE");
if (benefits == 'b' || benefits == 'B')
benefitsCost = grossPay * BENEFITSRATE;
else benefitsCost = 0;
netPay = grossPay - (benefitsCost + tax);
System.out.printf("%-10s %-10s %-10.2f %-10.2f %-10.2f %-10.2f %-10.2f %-10.2f\n",
last, first, hoursWorked, rate, tax, benefitsCost, grossPay, netPay);__
}// end of while
}
}
When run with the data file:
Smith John 37.5 7.35 s b
Lewis Larry 45.0 5.50 s n
Jones James 55.0 8.20 m b
The output is :
Last
Name
First
Name
Hours
Worked
Pay
Rate
Tax
Cost
Benefits
Cost
Gross
Pay
Net
Pay
Smith
Lewis
Jones
John
Larry
James
37.50
45.00
55.00
7.35
5.50
8.20
35.83
32.17
76.67
8.27
0.00
13.53
275.63
247.50
451.00
231.52
215.32
360.80
Writing Data to an output file
The simplest method to write to a text file using stream I/O is by using the class PrintWriter. We declare an
instance of PrintWriter by:
PrintWriter identifier = new PrintWriter(file name string or file instance);
ie: PrintWriter out = new PrintWriter(“c:\\cs110\\java\\output.dat”);
File outFile = new File(“c:\\cs110\\java\\output.txt”);
PrintWriter output = new PrintWriter(outFile);
This opens an output stream associated with the indicated file. IF the file already exists it is emptied before
new data is written into it. IF it does not exist it is created.
PrintWriter allows us to use the print, println, and printf methods with which we are already familiar.
Other methods we should be familiar with are:
o close() -- This methods closes the output stream. It must be performed on an output file
before the method terminates, otherwise the output file may be corrupted.
o flush() -- Flushes any remaining data in the internal buffer to the output file.
import java.io.*;
public class testOutput2 {
public static void main(String[] args) throws IOException {
File outFile = new File("c:\\cs110\\java\\outputtest.dat");
PrintWriter out = new PrintWriter(outFile);
char aChar = 'A';
for (int j=0; j < 10; j++){
for(int i=0; i<30; i++)out.print(aChar);
out.println();
aChar++;
} // end for
out.flush();
out.close();
}// end main
}
Sample output
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
Class File, and file operations
In all of the previous examples we have assumed that the input or output file name was valid, or simply
passed the error off to the operating system. There is another class in Java “File” which allows us to create a
connection to a file or directory, and then test it before creating an instance of FileReader or PrintWriter.
Class “File” in package “java.io” allows us to associate a “file” object to a physical file or a directory.
Once the connection is created, we can do many useful operations on the file, such as checking that it exists,
deleting it, or even searching a directory. The constructor for class FILE has several form :
(1) File myFile = new File(“c:\\cs110\\java\\xyz.txt”);
is a fully qualified reference to a file containing an exact path. This creates file instance myFile and
“associates” it with the text file. Note to specify slashes (as in windows) in a path name, you must
use two slashes. Since ‘\’ is a control character.
(2) File myFile = new File(“c:\\cs110\\java”, “xyz.txt”);
There is also a variation of the constructor for “File” that separates the “path” from the “file name”;
(3) File myDir = new File (“c:\\cs110\\java”);
and
File myFile = new File(myDir, “xyz.txt”);
We can also declare an instance to the directory name separately from the file itself. This would
simplify the access to multiple files in the same directory.
Once we have a file instance (which is a File object), some of the operations we can perform on files
are :







exists() : This method tests the object to see if the physical file or directory exists.
isDirectory() : Tests to see if the file instance points to a valid directory.
isFile() : Tests to see if the object is a file.
getAbsolutePath() : returns a string containing the absolute path to the file, consisting of the full
path, and file name.
delete(): deletes the file or directory associated with the file instance.
list() : returns an array of strings listing all of the files and directories contained in the directory
represented by the file instance.
mkdir(): creates the directory represented by this abstract path name.
Example 1:
import java.io.*;
public class testFileClass {
public static void main(String[] args) {
File inFile = new File("c:\\cs110\\java\\student.txt");
if ( inFile.exists() )
System.out.println("The file " + inFile.getAbsolutePath() +
" exists!!");
else
System.out.println("The file " + inFile.getAbsolutePath() +
" does not exist!!");
File inFile2 = new File("c:\\cs110\\java\\student2.dat");
if ( inFile2.exists() )
System.out.println("The file " + inFile2.getAbsolutePath() +
" exists!!");
else
System.out.println("The file " + inFile2.getAbsolutePath() +
" does not exist!!");
File myDir = new File("c:\\cs110\\java");
if ( myDir.isDirectory() ){
File myFile = new File(myDir, "student.txt");
System.out.println("The directory " + myDir.getAbsolutePath()
+ " exists, accessing file " +
myFile.getAbsolutePath());
if (myFile.isFile())
System.out.println(myFile.getAbsolutePath() + " is a file. ");
else
System.out.println(myFile.getAbsolutePath() + " is not a file");
}
else
System.out.println(" Invalid directory name");
String [] fileList = myDir.list();
System.out.println("The files in " + myDir.getAbsolutePath() + " are:");
for (int i=0; i< fileList.length; i++)
System.out.println(fileList[i]);
}
}
The results of executing this program are:
The file c:\cs110\java\student.txt exists!!
The file c:\cs110\java\student2.dat does not exist!!
The directory c:\cs110\java exists, accessing file
c:\cs110\java\student.txt
c:\cs110\java\student.txt is a file.
The files in c:\cs110\java are:
evaluating_expressions.doc
h1p1.java
h1p2.java
h1p4.java
student.txt
testFileClass.class
testFileClass.java
Download