AhmadLang / Java, How To Program, 2004
.pdf
(This item is displayed on page 676 in the print version)
[View full size image]
To facilitate the retrieval of specific records from a file, at least one field in each record is chosen as a record key. A record key identifies a record as belonging to a particular person or entity and is unique to each record. This field typically is used to search and sort records. In the payroll record described previously, the employee identification number normally would be chosen as the record key.
There are many ways to organize records in a file. The most common is called a sequential file, in which records are stored in order by the record-key field. In a payroll file, records are placed in ascending order by employee identification number.
Most businesses store data in many different files. For example, companies might have payroll files, accounts receivable files (listing money due from clients), accounts payable files (listing money due to suppliers), inventory files (listing facts about all the items handled by the business) and many others. Often, a group of related files is called a database. A collection of programs designed to create and manage databases is called a database management system (DBMS). We discuss this topic in Chapter 25, Accessing Databases with JDBC
[Page 675 (continued)]
14.3. Files and Streams
Java views each file as a sequential stream of bytes (Fig. 14.2). Every operating system provides a mechanism to determine the end of a file, such as an end-of-file marker or a count of the total bytes in the file that is recorded in a system-maintained administrative data structure. A Java program processing a stream of bytes simply receives an indication from the operating system when the program reaches the end of the streamthe program does not need to know how the underlying platform represents files or streams. In some cases, the end-of-file indication occurs as an exception. In other cases, the indication is a return value from a method invoked on a stream-processing object.
[Page 676]
Figure 14.2. Java's view of a file of n bytes.
[View full size image]
File streams can be used to input and output data as either characters or bytes. Streams that input and output bytes to files are known as byte-based streams, storing data in its binary format. Streams that input and output characters to files are known as character-based streams, storing data as a sequence of characters. For instance, if the value 5 were being stored using a byte-based stream, it would be stored in the binary format of the numeric value 5, or 101. If the value 5 were being stored using a character-based stream, it would be stored in the binary format of the character 5, or 00000000 00110101 (this is the binary for the numeric value 53, which indicates the character 5 in the Unicode character sets). The difference between the numeric value 5 and the character 5 is that the numeric value can be used as an integer, whereas the character 5 is simply a character that can be used in a string of text, as in "Sarah Miller is 15 years old". Files that are created using byte-based streams are referred to as binary files, while files created using character-based streams are referred to as text files. Text files can be read by text editors, while binary files are read by a program that converts the data to a human-readable format.
[Page 677]
A Java program opens a file by creating an object and associating a stream of bytes or characters with it. The classes used to create these objects are discussed shortly. Java can also associate streams with different devices. In fact, Java creates three stream objects that are associated with devices when a Java program begins executingSystem.in, System.out and System.err. Object System.in (the standard input stream object) normally enables a program to input bytes from the keyboard; object System.out (the standard output stream object) normally enables a program to output data to the screen; and object System.err (the standard error stream object) normally enables a program to output error messages to the screen. Each of these streams can be redirected. For System.in, this capability enables the program to read bytes from a different source. For System.out and System.err, this capability enables the output to be sent to a different location, such as a file on disk. Class System provides methods setIn, setOut and setErr to redirect the standard input, output and error streams, respectively.
Java programs perform file processing by using classes from package java.io. This package includes definitions for stream classes, such as FileInputStream (for byte-based input from a file),
FileOutputStream (for byte-based output to a file), FileReader (for character-based input from a file) and FileWriter (for character-based output to a file). Files are opened by creating
objects of these stream classes, which inherit from classes InputStream, OutputStream, Reader and
Writer, respectively (these classes will be discussed later in this chapter). Thus, the methods of these stream classes can all be applied to file streams as well.
Java contains classes that enable the programmer to perform input and output of objects or variables of primitive data types. The data will still be stored as bytes or characters behind the scenes, allowing the programmer to read or write data in the form of integers, strings, or other data types without having to worry about the details of converting such values to byte-format. To perform such input and output, objects of classes ObjectInputStream and ObjectOutputStream can be used together with the byte-based file stream classes FileInputStream and FileOutputStream (these classes will be discussed in more detail shortly). The complete hierarchy of classes in package java.io can be viewed in the online documentation at
java.sun.com/j2se/5.0/docs/api/java/io/package-tree.html
Each indentation level in the hierarchy indicates that the indented class extends the class under which it is indented. For example, class InputStream is a subclass of Object. Click a class's name in the hierarchy to view the details of the class.
As you can see in the hierarchy, Java offers many classes for performing input/output operations. We use several of these classes in this chapter to implement file-processing programs that create and manipulate sequential-access files and random-access files (discussed in Section 14.7). We also include a detailed example on class File, which is useful for obtaining information about files and directories. In Chapter 24, Networking, we use stream classes extensively to implement networking applications. Several other classes in the java.io package that we do not use in this chapter are discussed briefly in Section 14.8.
[Page 678]
In addition to the classes in this package, character-based input and output can be performed with classes Scanner and Formatter. Class Scanner is used extensively to input data from the keyboard. As we will see, this class can also read data from a file. Class Formatter enables formatted data to be output to the screen or to a file in a manner similar to System.out.printf. Chapter 28, Formatted Output, presents the details of formatted output with System.out.printf. All these features can be used to format text files as well.
Figure 14.4Fig. 14.5 demonstrate class File. The application prompts the user to enter a file name or directory name, then outputs information about the file name or directory name input.
Figure 14.4. File class used to obtain file and directory information.
1// Fig. 14.4: FileDemonstration.java
2// Demonstrating the File class.
3import java.io.File;
4
5public class FileDemonstration
6{
7 // display information about file user specifies
8public void analyzePath( String path )
9{
10// create File object based on user input
11File name = new File( path );
12
13 if ( name.exists() ) // if name exists, output information about it
14{
15// display file (or directory) information
16System.out.printf(
17 |
%s%s\n%s\n%s\n%s\n%s%s\n%s%s\n%s%s\n%s%s\n%s%s", |
||
18 |
name.getName() " exists", |
|
|
19 |
( name.isFile() ? "is a file" : "is not a |
file" ), |
|
20 |
( name.isDirectory() ? "is a directory" : |
|
|
21 |
"is not a directory" ), |
|
|
22 |
( name.isAbsolute() ? "is |
absolute path" |
: |
23 |
"is not absolute path" |
), "Last modified: ", |
|
24 |
name.lastModified(), "Length: ", name.length(), |
||
25 |
"Path: ", name.getPath(), |
"Absolute path: ", |
|
26 |
name.getAbsolutePath(), "Parent: ", name.getParent() ); |
||
27 |
|
|
|
28if ( name.isDirectory() ) // output directory listing
29{
30 |
String directory[] = name.list(); |
31 |
System.out.println( "\n\nDirectory contents:\n" ); |
32 |
|
33 |
for ( String directoryName : directory ) |
34 |
System.out.printf( "%s\n", directoryName ); |
35} // end else
36} // end outer if
37else // not file or directory, output error message
38{
39System.out.printf( "%s %s", path, "does not exist." );
40} // end else
41} // end method analyzePath
42} // end class FileDemonstration
Figure 14.5. Testing class FileDemonstration.
(This item is displayed on page 681 in the print version)
1// Fig. 14.5: FileDemonstrationTest.java
2// Testing the FileDemonstration class.
3import java.util.Scanner;
4
5public class FileDemonstrationTest
6{
7public static void main( String args[] )
8{
9Scanner input = new Scanner( System.in );
10FileDemonstration application = new FileDemonstration();
12System.out.print( "Enter file or directory name here: " );
13application.analyzePath( input.nextLine() );
14} // end main
15 } // end class FileDemonstrationTest
Enter file or directory name here: C:\Program Files\Java\jdk1.5.0\demo\jfc jfc exists
is not a file is a directory
is absolute path
Last modified: 1083938776645 Length: 0
Path: C:\Program Files\Java\jdk1.5.0\demo\jfc
Absolute path: C:\Program Files\Java\jdk1.5.0\demo\jfc Parent: C:\Program Files\Java\jdk1.5.0\demo
Directory contents:
CodePointIM
FileChooserDemo
Font2DTest
Java2D
Metalworks
Notepad
SampleTree
Stylepad
SwingApplet
SwingSet2
TableExample
Enter file or directory name here:
C:\Program Files\Java\jdk1.5.0\demo\jfc\Java2D\readme.txt readme.txt exists
is a file
is not a directory is absolute path
Last modified: 1083938778347 Length: 7501
Path: C:\Program Files\Java\jdk1.5.0\demo\jfc\Java2D\readme.txt
Absolute path: C:\Program Files\Java\jdk1.5.0\demo\jfc\Java2D\readme.txt Parent: C:\Program Files\Java\jdk1.5.0\demo\jfc\Java2D
[Page 682]
The program begins by prompting the user for a file or directory (line 12 of Fig. 14.5). Line 13 inputs the file name or directory name and passes it to method analyzePath (lines 841 of Fig. 14.4). The method creates a new File object (line 11) and assigns its reference to name. Line 13 invokes File method exists to determine whether the name input by the user exists (either as a file or as a directory) on the disk. If the name input by the user does not exist, control proceeds to lines 3740 and displays a message to the screen containing the name the user typed, followed by "does not exist." Otherwise, the body of the if statement (lines 1336) executes. The program outputs the name of the file or directory (line 18), followed by the results of testing the File object with isFile (line 19), isDirectory (line 20) and isAbsolute (line 22). Next, the program displays the values returned by lastModified (line 24), length (line 24), getPath (line 25), getAbsolutePath (line 26) and getParent (line 26). If the File object represents a directory (line 28), the program obtains a list of the directory's contents as an array of Strings by using File method list (line 30) and displays the list on the screen.
The first output of this program demonstrates a File object associated with the jfc directory from the
Java 2 Software Development Kit. The second output demonstrates a File object associated with the readme.txt file from the Java 2D example that comes with the Java 2 Software Development Kit. In both cases, we specified an absolute path on our personal computer.
A separator character is used to separate directories and files in the path. On a Windows computer, the separator character is a backslash (\) character. On a UNIX workstation, it is a forward slash (/) character. Java processes both characters identically in a path name. For example, if we were to use the path
c:\Program Files\Java\jdk1.5.0\demo/jfc
which employs each separator character, Java still processes the path properly. When building strings that represent path information, use File.pathSeparator to obtain the local computer's proper separator character rather than explicitly using / or \. This constant returns a String consisting of one characterthe proper separator for the system.
Common Programming Error 14.1
Using \ as a directory separator rather than \\ in a string literal is a logic error. A single \ indicates that the \ followed by the next character represents an escape sequence. Use \\ to insert a \ in a string literal.
[Page 682 (continued)]
14.5. Sequential-Access Text Files
In this section, we create and manipulate sequential-access files. As mentioned earlier, these are files in which records are stored in order by the record-key field. We first demonstrate sequential-access files using text files, allowing the reader to quickly create and edit human-readable files. In the subsections of this chapter we discuss creating, writing data to, reading data from and updating sequential-access text files. We also include a credit-inquiry program that retrieves specific data from a file.
14.5.1. Creating a Sequential-Access Text File
Java imposes no structure on a filenotions such as a record do not exist as part of the Java language. Therefore, the programmer must structure files to meet the requirements of the intended application. In the following example, we see how to impose a record structure on a file.
[Page 683]
The program in Fig. 14.6Fig. 14.7 and Fig. 14.9 creates a simple sequential-access file that might be used in an accounts receivable system to help keep track of the amounts owed to a company by its credit clients. For each client, the program obtains from the user an account number, the client's name and the client's balance (i.e., the amount the client owes the company for goods and services received). The data obtained for each client constitutes a "record" for that client. The account number is used as the record key in this applicationthe file will be created and maintained in account number order. The program assumes that the user enters the records in account number order. In a comprehensive accounts receivable system (based on sequential-access files), a sorting capability would be provided so that the user could enter the records in any order. The records would then be sorted and written to the file.
Figure 14.6. AccountRecord maintains information for one account.
(This item is displayed on pages 683 - 684 in the print version)
1 |
// |
Fig. |
14 |
.6: AccountRecord.java |
|
2 |
// |
A class |
that represents one |
record of information. |
|
3 |
package |
com.deitel.jhtp6.ch14; |
// packaged for reuse |
||
4 |
|
|
|
|
|
5public class AccountRecord
6{
7private int account;
8private String firstName;
9private String lastName;
10private double balance;
12// no-argument constructor calls other constructor with default values
13public AccountRecord()
14 |
{ |
|
|
|
15 |
|
this ( |
0, "", "", |
0.0 ); // call four-argument constructor |
16 |
} |
// end |
no-argument |
AccountRecord constructor |
17 |
|
|
|
|
18// initialize a record
19public AccountRecord( int acct, String first, String last, double bal )
20{
21setAccount( acct );
22setFirstName( first );
23setLastName( last );
24setBalance( bal );
25} // end four-argument AccountRecord constructor
26
27// set account number
28public void setAccount( int acct )
29{
30account = acct;
31} // end method setAccount
32
33// get account number
34public int getAccount()
35{
36return account;
37} // end method getAccount
39// set first name
40public void setFirstName( String first )
41{
42firstName = first;
43} // end method setFirstName
45// get first name
46public String getFirstName()
47{
48return firstName;
49} // end method getFirstName
51// set last name
52public void setLastName( String last )
53{
54lastName = last;
55} // end method setLastName
57// get last name
58public String getLastName()
59{
60return lastName;
61} // end method getLastName
63// set balance
64public void setBalance( double bal )
65{
66balance = bal;
67} // end method setBalance
69// get balance
70public double getBalance()
71{
72return balance;
73} // end method getBalance
74} // end class AccountRecord
Figure 14.7. Creating a sequential text file.
(This item is displayed on pages 686 - 687 in the print version)
1 // Fig. 14.7: CreateTextFile.java
2 // Writing data to a text file with class Formatter.
3import java.io.FileNotFoundException;
4import java.lang.SecurityException;
5import java.util.Formatter;
6import java.util.FormatterClosedException;
7import java.util.NoSuchElementException;
8import java.util.Scanner;
9
10 import com.deitel.jhtp6.ch14.AccountRecord; 11
12public class CreateTextFile
13{
14private Formatter output; // object used to output text to file
16// enable user to open file
17public void openFile()
18{
19try
20{
21output = new Formatter( "clients.txt" );
22} // end try
23catch ( SecurityException securityException )
24{
