A disk file organizes data on a massive storage device such as a disk device. The main advantage of a disk file is that it provides permanent data storage; a second advantage is that it can support a large amount of data. A third advantage of a disk file is that the data can be interchangeable among several computers, depending on the type of storage device used. On the same computer, disk files can be used by one or more different programs.
A disk file can be set up as the source of a data stream or as the destination of the data stream. In other words, the file can be associated with an input stream or with an output stream. Figure 15.2 illustrates the flow of data and the difference between an input and an output stream.
Figure 15.2: Input and output streams.
Text files are human-readable. They contain data that is coded as printable strings. A byte is coded as a single text character. For example, a KJP source program is stored in a text file with a .kpl extension. In the same manner, a Java source program is also stored in a text file. In simple terms, a text file consists of a sequence of characters. Lines are separated by two characters, carriage return (CR) and line feed (LF); these are placed at the end of a line by pressing the Enter key [1].
A binary file is not human-readable. Its data is stored in the same way as represented in memory. Especially for numeric data, the representation in memory is just ones and zeroes. A compiled program is stored in a binary file.
Binary files take less storage space and are more efficient to process. When reading or writing numeric data, there is no conversion from or to string format.
The normal procedure for a program that processes data on a file is the following:
Open the file for input or output. This step is called opening the file for input or output; it attaches the file to a stream.
Read data from the file or write data to the file.
Close the file.
For these file processing tasks, Java provides several library classes. Most of the classes for stream I/O are located in package java.io.
Java provides two predefined Java classes that are used to create objects for opening a text file for output, FileOutputStream and PrintWriter. The following statements declare the two object references and create the corresponding objects to an output text file called mydata.txt.
object myoutfile of class FileOutputStream object myoutstream of class PrintWriter . . . try begin create myoutfile of class FileOutputStream using "mydata.txt" create myoutstream of class PrintWriter using myoutfile endtry
The previous statements have connected the disk file to an output stream, myoutstream. This opening of the file could generate an exception if the file cannot be created. For this reason, the statements must appear in a try block. To handle the exception, a catch block must immediately follow.
catch parameters object e of class FileNotFoundException begin display "Error creating file mydata.txt" terminate endcatch
If the output file cannot be created, an exception is raised (thrown) and statements in the catch block display an error message related to the exception and terminate the program.
The output stream created is used for all output statements in the program with methods print and println of object reference myoutstream.
After the output file has been created, it can be used to write string data. The numeric data must first be converted to string. For example, to convert an integer value to a string value, function valueOf of the class String is invoked. The following statements declare a variable of type integer, int_val, declare a variable of type string, str_val, convert the value of the integer variable to a string, and assign the value to the string variable, str_val.
variables integer int_val string str_val . . . set str_val = call String.valueOf(int_val)
The following class, Fileproc, implements the solution of the salary problem that stores data about employees in a text file. Objects of class Employeec calculate the salary increase and the updated salary.
import all java.io description This program checks for an exception in the value of age, and writes data to an output file. */ class Fileproc is public description This is the main function of the application. An object of class Employeec calculates the salary increase and updates the salary. If the age is zero or negative, an exception is thrown and caught. This data is written to an output text file. */ function main is variables integer obj_age character more_data real increase real obj_salary string obj_name string str_age string str_inc string str_sal string file_name string lmessage // message for exception objects object emp_obj of class Employeec object myoutfile of class FileOutputStream object myoutstream of class PrintWriter // exception for negative age object lexecep_obj of class Exception begin set myoutstream = null display "Enter name for output file: " read file_name // open ouput file try begin create myoutfile of class FileOutputStream using file_name create myoutstream of class PrintWriter using myoutfile endtry catch parameters object e of class FileNotFoundException begin display "Error creating file mydata.txt" terminate endcatch set more_data = 'Y' while more_data equal 'Y' do display "Enter person name: " read obj_name display "Enter age: " read obj_age // Check for exception try begin if obj_age <= 0 then create lexecep_obj of class Exception using "Exception: age negative or zero" throw lexecep_obj endif endtry catch parameters object excobj of class Exception begin set lmessage = call getMessage of excobj display lmessage display "Retrying . . . " display "Enter age: " read obj_age endcatch // continue with processing display "Enter salary: " read obj_salary create emp_obj of class Employeec using obj_salary, obj_age, obj_name set increase = call sal_increase of emp_obj set obj_salary = get_salary() of emp_obj display "Employee name: ", obj_name display "increase: ", increase, " new salary: ", obj_salary // write to output file call println of myoutstream using obj_name set str_age = call String.valueOf using obj_age call println of myoutstream using str_age set str_inc =call String.valueOf using increase call println of myoutstream using str_inc set str_sal = call String.valueOf using obj_salary call println of myoutstream using str_sal display "More data? (Yy/Nn): " read more_data if more_data equal 'y' then set more_data = 'Y' endif endwhile call close of myoutstream endfun main endclass Fileproc
On the CD | The KJP code that implements class Fileproc is stored in the file Fileproc.kpl, and the Java code is stored in the file Fileproc.java. |
The program, composed of class Fileproc and class Employeec, displays the following input/output when it executes with the data shown:
----jGRASP exec: java Fileproc Enter name for output file: mydata.txt Enter person name: James Bond Enter age: 54 Enter salary: 51800.75 Employee name: James Bond increase: 2331.034 new salary: 54131.785 More data? (Yy/Nn): y Enter person name: Jose M. Garrido Enter age: 48 Enter salary: 46767.50 Employee name: Jose M. Garrido increase: 2104.5376 new salary: 48872.04 More data? (Yy/Nn): y Enter person name: John B. Hunt Enter age: 38 Enter salary: 39605.65 Employee name: John B. Hunt increase: 1980.2825 new salary: 41585.93 More data? (Yy/Nn): n ----jGRASP: operation complete.
The output file, mytest.txt, was created and written by the program and has one data item per line with the following structure:
James Bond 54 2331.034 54131.785 Jose M. Garrido 48 2104.5376 48872.04 John B. Hunt 38 1980.2825 41585.93
Reading data from an input text file implies reading text lines from the input line. If the data items are numeric, then the source string must be converted to a numeric type. Another aspect of input text files is that the program that reads from the file has no information on the number of lines in the text file.
Java provides two predefined Java classes in the io package that are used to create objects for opening a text file for input, BufferedReader and FileReader. The following statements declare the two object references and create the corresponding objects for an input text file called "mydata.txt."
object myinfile of class BufferedReader object myreader of class FileReader . . . try begin create myreader of class FileReader using "mydata.txt" create myinfile of class BufferedReader using myreader endtry
Opening a text file for input can throw an exception if the file cannot be found. Therefore, the statements that create the two objects must appear in a try block. To handle the exception, a catch block must immediately follow.
catch parameters object excep of class FileNotFoundException begin display "Error opening file: ", file_name terminate endcatch
In a similar manner to dealing with the output file creation, if the input file cannot be opened, the statements shown in the catch block display an error message and terminate the program.
After opening the file for input, the program can read input streams from the file, line by line. The Java method readLine, which is defined in class BufferedReader, is invoked to read a line of text data. This data is assigned to a string variable. The statement to read a line of data must be placed in a try block because a reading error might occur. The exception is thrown by method readLine.
One additional complication, compared to writing a text file, is that it is necessary to check whether the file still has data; otherwise, there would be an attempt to read data even if there is no more data in the file.
When there is no more data in the file, the value of the text read is null. The following statements define a try block with a while loop, which repeatedly reads lines of text from the text file.
try begin // Read text line from input file set indata = call readLine of myinfile while indata not equal null do // get name set obj_name = indata . . . // read next line set indata = call readLine of myinfile endwhile endtry
The first statement in the try block reads a text line from the file. All subsequent reading is placed in the while loop.
Because the text file can only store string values, conversion is needed for numeric variables. For example, obj_salary and increase are variables of type double, so the string value read from the text file has to be converted to type double. The following statements read the text line (a string) from the file, and then convert the string value to a value of type double with method Double.parseDouble.
// get salary set indata = call readLine of myinfile set obj_salary = call Double.parseDouble using indata // get increase set indata = call readLine of myinfile set increase = call Double.parseDouble using indata
Method Integer.parseInt would be invoked if conversion were needed for an integer variable.
The following class, Rfileproc, reads the text file that was written by the program presented in Section 15.3.4. This data file has one value stored per line. The values of name, age, salary, and increase are each stored in a different line. The file stores these values for every person. The class computes and displays the total accumulated value of salary and the total accumulated value of increase for several persons.
import all java.io description Reads data from an input file, computes the total salary, total increase, and displays the data on the screen. */ class Rfileproc is public description This is the main function of the application. If an error occurs when opening the input file, an exception is thrown and caught. */ function main is variables integer obj_age double increase double obj_salary double total_sal double total_inc string obj_name string str_age string file_name string indata string lmessage // message for exception objects object myinfile of class BufferedReader object myreader of class FileReader // exception for negative age object lexecep_obj of class Exception begin set myinfile = null set total_sal = 0.0 set total_inc = 0.0 display "Enter name for input file: " read file_name try begin // open input file create myreader of class FileReader using file_name create myinfile of class BufferedReader using myreader endtry catch parameters object e of class FileNotFoundException begin display "Error opening file: ", file_name terminate endcatch // try begin // Read text line from input file set indata = call readLine of myinfile while indata not equal null do // get name set obj_name = indata // get age set indata = call readLine of myinfile set str_age = indata // get salary set indata = call readLine of myinfile set obj_salary = call Double.parseDouble using indata add obj_salary to total_sal // get increase set indata = call readLine of myinfile set increase = call Double.parseDouble using indata add increase to total_inc // // Display and continue with processing display "Employee name: ", obj_name, " age: ", str_age display " increase: ", increase, " salary: ", obj_salary // read next line from file set indata = call readLine of myinfile endwhile endtry catch parameters object myexc of class Exception begin display "Error reading file: ", file_name terminate endcatch display " --------------------", "--------------------------------" display "Total salary: ", total_sal display "Total increase: ", total_inc try begin call close of myinfile endtry catch parameters object exc2 of class IOException begin display "Error closing file: ", file_name terminate endcatch endfun main endclass Rfileproc
On the CD | The KJP code with the implementation of class Rfileproc is stored in the file Rfileproc.kpl. The corresponding Java code is stored in the file Rfileproc.java. |
When the program executes, it reads data from the text file "mydata.txt." The program gets the values for the individual data items (name, age, salary, and increase) and computes the total salary and increase. The following listing is the one displayed on the screen.
----jGRASP exec: java Rfileproc Enter name for input file: mydata.txt Employee name: James Bond age: 54 increase: 54131.785 salary: 2331.034 Employee name: Jose M. Garrido age: 48 increase: 48872.04 salary: 2104.5376 Employee name: John B. Hunt age: 38 increase: 41585.93 salary: 1980.2825 ------------------------------------ Total salary: 6415.8541000000005 Total increase: 144589.755 ----jGRASP: operation complete.
A text file usually contains lines with several values per line, each separated by white spaces or blanks. In this case, the program must read a line of text from the file, separate and retrieve the individual string values, and convert the values to the appropriate types (if needed). The program must repeat this for every line that it reads from the text file. The following text file has three lines, each with various values, some string values and some numeric values.
James_Bond 54 2331.034 54131.785 Jose_M._Garrido 48 2104.5376 48872.04 John_B._Hunt 38 1980.2825 41585.93
The Java class StringTokenizer facilitates separating the individual strings from a text line. The following statements declare and create an object of class StringTokenizer, read a line from the text file, and get two string variables, var1 and var2, from the line.
// declare object ref for tokenizer object tokenizer of class StringTokenizer // // read line from text file set line = call readLine of input_file // // create tokenizer object create tokenizer of class StringTokenizer using line // // get a string variable from line set var1 = call nextToken of tokenizer // // get another string variable from line set var2 = call nextToken of tokenizer
To get the number of substrings remaining on a line, the Java method countTokens can be invoked with the tokenizer object. This function returns a value of type integer. A similar function, hasMoreTokens, returns true if there are substrings on the line; otherwise, it returns false.
Class Lfileproc is similar to class Rfileproc, but it reads a line from the text file and separates the individual string variables for name, age, increase, and salary.
On the CD | The KJP code that implements class Lfileproc is stored in the file Lfileproc.kpl. The Java code is stored in the file Lfileproc.java. |
[1]In Unix, only LF is placed at the end of the line.