1. Understanding Computer Files

    Data items can be stored on two broad types of storage devices in a computer system:
    • Volatile storage is temporary; values that are volatile, such as those stored in variables, are lost when a computer loses power. Random access memory (RAM) is the temporary storage within a computer. When you write a Java program that stores a value in a variable, you are using RAM. Most computer professionals simply call volatile storage memory. • Nonvolatile storage is permanent storage; it is not lost when a computer loses power. When you write a Java program and save it to a disk, you are using permanent storage. A computer file is a collection of data stored on a nonvolatile device. Files exist on permanent storage devices, such as hard disks, USB drives, reels or cassettes of magnetic tape, and compact discs. You can categorize files by the way they store data: • Text files contain data that can be read in a text editor because the data has been encoded using a scheme such as ASCII or Unicode. (See Appendix B for more information on Unicode.) Some text files are data files that contain facts and figures, such as a payroll file that contains employee numbers, names, and salaries; some files are program files or application files that store software instructions. You have created many program files throughout this book. • Binary files contain data items that have not been encoded as text. Their contents are in binary format, which means that you cannot understand them by viewing them in a text editor. Examples include images, music, and the compiled program files with a .class extension that you have created using this book. Although their contents vary, files have many common characteristics—for example, each file has a size that specifies the space it occupies on a section of disk or other storage device, each file has a name, and each file has a specific time of creation.
  2. Using the Path and Files Classes

    You can use Java’s Path and Files classes to work with stored files. • The Path class is used to create objects that contain information about files and directories, such as their locations, sizes, creation dates, and whether they even exist. • The Files class is used to perform operations on files and directories, such as deleting them, determining their attributes, and creating input and output streams. You can include the following statement in a Java program to use both the Path and Files classes: import java.nio.file.*; The nio in java.nio stands for new input/output because its classes are “new” in that they were not developed until Java 7.
    Creating a Path
    To create a Path, you first determine the default file system on the host computer by using a statement such as the following: FileSystem fs = FileSystems.getDefault(); This statement creates a FileSystem object using the getDefault() method in the FileSystems class. The statement uses two different classes. The FileSystem class, without an ending s, is used to instantiate the object. FileSystems, with an ending s, is a class that contains factory methods, which assist in object creation. After you create a FileSystem object, you can define a Path using the getPath() method with it: Path path = fs.getPath("C:\\Java\\Chapter.13\\Data.txt"); Recall that the backslash is used as part of an escape sequence in Java. (For example, '\n' represents a newline character.) So, to enter a backslash as a path delimiter within a string, you must type two backslashes to indicate a single backslash. An alternative is to use the FileSystem method getSeparator(). This method returns the correct separator for the current operating system. For example, you can create a Path that is identical to the previous one using a statement such as the following: Path path = fs.getPath("C:" + fs.getSeparator() + "Java" + fs.getSeparator() + "Chapter.13" + fs.getSeparator() + "Data.txt"); Another way to create a Path is to use the Paths class (notice the name ends with s). The Paths class is a helper class that eliminates the need to create a FileSystem object. The Paths class get() method calls the getPath() method of the default file system without requiring you to instantiate a FileSystem object. You can create a Path object by using the following statement: Path path = Paths.get("C:\\Java\\Chapter.13\\SampleFile.txt"); After the Path is created, you use its identifier (in this case, filePath) to refer to the file and perform operations on it. C:\Java\Chapter.13\SampleFile.txt is the full name of a stored file when the operating system refers to it, but the path is known as filePath within the application. The idea of a file having one name when referenced by the operating system and a different name within an application is similar to the way a student known as Arthur in school might be Junior at home. When an application declares a path and you want to use the application with a different file, you would change only the String passed to the instantiating method. Every Path is either absolute or relative. • An absolute path is a complete path; it does not need any other information to locate a file on a system. A full path such as C:\Java\Chapter.13\SampleFile.txt is an absolute path. • A relative path depends on other path information. A simple path such as SampleFile.txt is relative. When you work with a path that contains only a filename, the file is assumed to be in the same folder as the program using it. Similarly, when you refer to a relative path such as Chapter.13\SampleFile.txt (without the drive letter or the top-level Java folder), the Chapter.13 folder is assumed to be a subfolder of the current directory, and SampleFile.txt is assumed to be within the folder
    Retrieving Information About a Path
    Table summarizes several useful Path methods. As you have learned with other classes, the toString() method is overridden from the Object class; it returns a String representation of the Path. Basically, this is the list of path elements separated by copies of the default separator for the operating system. The getFileName() method returns the last element in a list of pathnames; frequently this is a filename, but it might be a folder name.
    MethodDescription
    String toString()Returns the String representation of the Path, eliminating double backslashes
    Path getFileName()Returns the file or directory denoted by this Path; this is the last item in the sequence of name elements
    int getNameCount()Returns the number of name elements in the Path
    Path getName(int)Returns the name in the position of the Path specified by the integer parameter
    A Path’s elements are accessed using an index. The top-level element in the directory structure is located at index 0; the lowest element in the structure is accessed by the getName() method, and has an index that is one less than the number of items on the list. You can use the getNameCount() method to retrieve the number of names in the list and the getName(int) method to retrieve the name in the position specified by the argument.
    import java.nio.file.*; public class PathDemo { public static void main(String[] args) { Path filePath = Paths.get("C:\\Java\\Chapter.13\\Data.txt"); int count = filePath.getNameCount(); System.out.println("Path is " + filePath.toString()); System.out.println("File name is " + filePath.getFileName()); System.out.println("There are " + count + " elements in the file path"); for(int x = 0; x < count; ++x) System.out.println("Element " + x + " is " + filePath.getName(x)); } }
    Converting a Relative Path to an Absolute One
    import java.util.Scanner; import java.nio.file.*; public class PathDemo2 { public static void main(String[] args) { String name; Scanner keyboard = new Scanner(System.in); System.out.print("Enter a file name >> "); name = keyboard.nextLine(); Path inputPath = Paths.get(name); Path fullPath = inputPath.toAbsolutePath(); System.out.println("Full path is " + fullPath.toString()); } }
    Checking File Accessibility
    To verify that a file exists and that the program can access it as needed, you can use the checkAccess() method. The following import statement allows you to access constants that can be used as arguments to the method: import static java.nio.file.AccessMode.*; Assuming that you have declared a Path named filePath, the syntax you use with checkAccess() is as follows: filePath.getFileSystem().provider().checkAccess(); You can use any of the following as arguments to the checkAccess() method: • No argument—Checks that the file exists • READ—Checks that the file exists and that the program has permission to read the file • WRITE—Checks that the file exists and that the program has permission to write to the file • EXECUTE—Checks that the file exists and that the program has permission to execute the file
    import java.nio.file.*; import static java.nio.file.AccessMode.*; import java.io.IOException; public class PathDemo3 { public static void main(String[] args) { Path filePath = Paths.get("C:\\Java\\Chapter.13\\PathDemo.class"); System.out.println("Path is " + filePath.toString()); try { filePath.getFileSystem().provider().checkAccess (filePath, READ, EXECUTE); System.out.println("File can be read and executed"); } catch(IOException e) { System.out.println ("File cannot be used for this application"); } } }
    Deleting a Path
    The Files class delete() method accepts a Path parameter and deletes the last element (file or directory) in a path or throws an exception if the deletion fails. For example: • If you try to delete a file that does not exist, a NoSuchFileException is thrown. • A directory cannot be deleted unless it is empty. If you attempt to delete a directory that contains files, a DirectoryNotEmptyException is thrown. • If you try to delete a file but you don’t have permission, a SecurityException is thrown. • Other input/output errors cause an IOException. Figure shows a program that displays an appropriate message in each of the preceding scenarios after attempting to delete a file.
    import java.nio.file.*; import java.io.IOException; public class PathDemo4 { public static void main(String[] args) { Path filePath = Paths.get("C:\\Java\\Chapter.13\\Data.txt"); try { Files.delete(filePath); System.out.println("File or directory is deleted"); } catch (NoSuchFileException e) { System.out.println("No such file or directory"); } catch (DirectoryNotEmptyException e) { System.out.println("Directory is not empty"); } catch (SecurityException e) { System.out.println("No permission to delete"); } catch (IOException e) { System.out.println("IO exception"); } } }
    Determining File Attributes
    You can use the readAttributes() method of the Files class to retrieve useful information about a file. The method takes two arguments—a Path object and BasicFileAttributes.class—and returns an instance of the BasicFileAttributes class. You might create an instance with a statement such as the following: BasicFileAttributes attr = Files.readAttributes(filePath, BasicFileAttributes.class); After you have created a BasicFileAttributes object, you can use several methods for retrieving information about a file. For example, the size() method returns the size of a file in bytes. Methods such as creationTime() and lastModifiedTime() return important file times. Figure contains a program that uses these methods.
    import java.nio.file.*; import java.nio.file.attribute.*; import java.io.IOException; public class PathDemo5 { public static void main(String[] args) { Path filePath = Paths.get("C:\\Java\\Chapter.13\\Data.txt"); try { BasicFileAttributes attr = Files.readAttributes(filePath, BasicFileAttributes.class); System.out.println("Creation time " + attr.creationTime()); System.out.println("Last modified time " + attr.lastModifiedTime()); System.out.println("Size " + attr.size()); } catch(IOException e) { System.out.println("IO Exception"); } } }
    Frequently, you don’t care about a file’s exact FileTime value, but you are interested in comparing two files to discover which is newer. Figure demonstrates the compareTo() method which returns a value of less than 0 if the first FileTime comes before the argument’s FileTime. The method returns a value of greater than 0 if the first FileTime is later than the argument’s, and it returns 0 if the FileTime values are the same.
    import java.nio.file.*; import java.nio.file.attribute.*; import java.io.IOException; public class PathDemo6 { public static void main(String[] args) { Path file1 = Paths.get("C:\\Java\\Chapter.13\\Data.txt"); Path file2 = Paths.get("C:\\Java\\Chapter.13\\Data2.txt"); try { BasicFileAttributes attr1 = Files.readAttributes(file1, BasicFileAttributes.class); BasicFileAttributes attr2 = Files.readAttributes(file2, BasicFileAttributes.class); FileTime time1 = attr1.creationTime(); FileTime time2 = attr2.creationTime(); System.out.println("file1's creation time is: " + time1); System.out.println("file2's creation time is: " + time2); if(time1.compareTo(time2) < 0) System.out.println("file1 was created before file2"); else if(time1.compareTo(time2) > 0) System.out.println("file1 was created after file2"); else System.out.println ("file1 and file2 were created at the same time"); } catch(IOException e) { System.out.println("IO Exception"); } } }
  3. File Organization, Streams, and Buffers
    Most businesses generate and use large quantities of data every day. You can store data in variables within a program, but such storage is temporary. When the application ends, the variables no longer exist and the data values are lost because variables are stored in the computer’s main or primary memory (RAM). When you need to retain data for any significant amount of time, you must save the data on a permanent, secondary storage device, such as a disk. Businesses organize data in a hierarchy. The smallest useful piece of data to most users is the character. A character can be any letter, number, or other special symbol (such as a punctuation mark) that comprises data. Characters are made up of bits (the zeros and ones that represent computer circuitry), but people who use data typically do not care whether the internal representation for an A is 01000001 or 10111110. Rather, they are concerned with the meaning of A—for example, it might represent a grade in a course, a person’s initial, or a company code. In computer terminology, a character can be any group of bits, and it does not necessarily represent a letter or number; for example, some “characters” produce a sound or control the display. Also, characters are not necessarily created with a single keystroke; for example, escape sequences are used to create the '\n' character, which starts a new line, and '\\', which represents a single backslash. Sometimes, you can think of a character as a unit of information instead of data with a particular appearance. For example, the mathematical character pi (π) and the Greek letter pi look the same, but have two different Unicode values. When businesses use data, they group characters into fields. A field is a group of characters that has some meaning. For example, the characters T, o, and m might represent your first name. Other data fields might represent items such as last name, Social Security number, zip code, and salary. Fields are grouped together to form records. A record is a collection of fields that contain data about an entity. For example, a person’s first and last names, Social Security number, zip code, and salary represent that person’s record. When programming in Java, you have created many classes, such as an Employee class or a Student class. You can think of the data typically stored in each of these classes as a record. These classes contain individual variables that represent data fields. A business’s data records usually represent a person, item, sales transaction, or some other concrete object or event. Records are grouped to create files. Data files consist of related records, such as a company’s personnel file that contains one record for each employee. Some files have only a few records; perhaps your professor maintains a file for your class with 25 records—one record for each student. Other files contain thousands or even millions of records. For example, an insurance company maintains a file of policyholders, and a mail-order catalog company maintains a file of available items. A data file can be used as a sequential access file when each record is accessed one after another in the order in which it was stored. Most frequently, each record is stored in order based on the value in some field; for example, employees might be stored in Social Security number order, or inventory items might be stored in item number order. When records are not used in sequence, the file is used as a random access file. You learn more about random access files later in this chapter. When records are stored in a data file, their fields can be organized one to a line, or a character can be used to separate them. A file of comma-separated values (CSV) is one in which each value in a record is separated from the next by a comma; CSV is a widely used format for files used in all sorts of applications, including databases and spreadsheets. Later in this chapter, you will see examples of CSV files. Before an application can use a data file, it must open the file. A Java application opens a file by creating an object and associating a stream of bytes with it. Similarly, when you finish using a file, the program should close the file—that is, make it no longer available to your application. If you fail to close an input file—a file from which you are reading data— there usually are no serious consequences; the data items still exist in the file. However, if you fail to close an output file—a file to which you are writing data—the data might become inaccessible. You should always close every file you open, and usually you should close the file as soon as you no longer need it. When you leave a file open for no reason, you use computer resources, and your computer’s performance suffers. Also, particularly within a network, another program might be waiting to use the file. Whereas people view a file as a series of records, with each record containing data fields, Java does not automatically attribute such meaning to a file’s contents. Instead, Java simply views a file as a series of bytes. When you perform an input operation in an application, you can picture bytes flowing into your program from an input device through a stream, which functions as a pipeline or channel. When you perform output, some bytes flow out of your application through another stream to an output device, as shown in Figure 13-14. A stream is an object, and like all objects, streams have data and methods. The methods allow you to perform actions such as opening, closing, reading, and writing. Most streams flow in only one direction; each stream is either an input or output stream. (Later in this chapter, you will learn that random access files use streams that flow in two directions.) You might open several streams at once within an application. For example, an application that reads a data disk and separates valid records from invalid ones might require three streams: • The data arrives via an input stream. • One output stream writes some records to a file of valid records. • Another output stream writes other records to a file of invalid records. Input and output operations are usually among the slowest operations in any computerized system because of limitations imposed by the hardware. For that reason, professional programs often employ buffers. In Chapter 7, you learned that the StringBuilder object sets aside a memory block called a buffer. The same term describes a memory location where bytes are held after they are logically output but before they are sent to the output device. Using a buffer to accumulate input or output before issuing the actual IO command improves program performance. When you use an output buffer, you sometimes flush it before closing it. Flushing clears any bytes that have been sent to a buffer for output but have not yet been output to a hardware device.
  4. Using Java’s IO Classes

    Figure shows a partial hierarchical relationship of some of the classes Java uses for input and output (IO) operations; it shows that InputStream, OutputStream, and Reader are subclasses of the Object class. All three of these classes are abstract. As you learned in Chapter 11, abstract classes contain methods that must be overridden in their child classes. The figure also shows the major IO child classes that you will study in this chapter. The capabilities of these classes are summarized in Table. As its name implies, the OutputStream class can be used to produce output. Table shows some of the class’s common methods. You can use OutputStream to write all or part of an array of bytes. When you finish using an OutputStream, you usually want to flush and close it. Java’s System class contains a PrintStream object named System.out; you have used this object extensively in the book, along with its print() and println() methods. Besides System.out, the System class defines a PrintStream object named System.err. The output from System.err and System.out can go to the same device; in fact,System.err and System.out are both directed by default to the command line on the monitor. The difference is that System.err is usually reserved for error messages, and System.out is reserved for valid output. You can direct either System.err or System.out to a new location, such as a disk file or printer. For example, you might want to keep a hard copy (printed) log of the error messages generated by a program, but direct the standard output to a disk file. Object | +--InputStream | | | +--FileInputStream | | | +--FilterInputStream | | | +--BufferedInputStream | +--OutputStream | | | +--FileOutputStream | | | +--FilterOutputStream | | | +--BufferedOutputStream | | | +--PrintStream | +--Reader | +--BufferedReader | +--BufferedWriter
    ClassDescription
    InputStreamAbstract class that contains methods for performing input
    FileInputStreamChild of InputStream that provides the capability to read from disk files
    BufferedInputStreamChild of FilterInputStream, which is a child of InputStream; BufferedInputStream handles input from a system’s standard (or default) input device, usually the keyboard
    OutputStreamAbstract class that contains methods for performing output
    FileOutputStreamChild of OutputStream that allows you to write to disk files
    BufferedOutputStreamChild of FilterOutputStream, which is a child of OutputStream; BufferedOutputStream handles input from a system’s standard (or default) output device, usually the monitor
    PrintStreamChild of FilterOutputStream, which is a child of OutputStream; System.out is a PrintStream object
    ReaderAbstract class for reading character streams; the only methods that a subclass must implement are read (char[], int, int) and close()
    BufferedReaderReads text from a character-input stream, buffering characters to provide for efficient reading of characters, arrays, and lines
    BufferedWriterWrites text to a character-output stream, buffering characters to provide for the efficient writing of characters, arrays, and lines
    OutputStream MethodDescription
    void close()Closes the output stream and releases any system resources associated with the stream
    void flush()Flushes the output stream; if any bytes are buffered, they will be written
    void write(byte[] b)Writes all the bytes to the output stream from the specified byte array
    void write(byte[] b, int off, int len)Writes bytes to the output stream from the specified byte array starting at offset position off for a length of len characters
    Although you usually have no need to do so, you can create your own OutputStream object and assign System.out to it. Figure shows how this works. The application declares a String of letter grades allowed in a course. Then, the getBytes() method converts the String to an array of bytes. An OutputStream object is declared, and System.out is assigned to the OutputStream reference in a try block.
    import java.io.*; public class ScreenOut { public static void main(String[] args) { String s = "ABCDF"; byte[] data = s.getBytes(); OutputStream output = null; try { output = System.out; output.write(data); output.flush(); output.close(); } catch(Exception e) { System.out.println("Message: " + e); } } }
    Writing to a File
    Instead of assigning the standard output device to OutputStream, you can assign a file. To accomplish this, you can construct a BufferedOutputStream object and assign it to the OutputStream. If you want to change an application’s output device, you don’t have to modify the application except to assign a new object to the OutputStream; the rest of the logic remains the same. Java lets you assign a file to a Stream object so that screen output and file output work in exactly the same manner. You can create a writeable file by using the Files class newOutputStream() method. You pass a Path and a StandardOpenOption argument to this method. The method creates a file if it does not already exist, opens the file for writing, and returns an OutputStream that can be used to write bytes to the file. Table shows the StandardOpenOption arguments you can use as the second argument to the newOutputStream() method. If you do not specify any options and the file does not exist, a new file is created. If the file exists, it is truncated. In other words, specifying no option is the same as specifying both CREATE and TRUNCATE_EXISTING.
    StandardOpenOptionDescription
    WRITEOpens the file for writing
    APPENDAppends new data to the end of the file; use this option with WRITE or CREATE
    TRUNCATE_EXISTINGTruncates the existing file to 0 bytes so the file contents are replaced; use this option with the WRITE option
    CREATE_NEWCreates a new file only if it does not exist; throws an exception if the file already exists
    CREATEOpens the file if it exists or creates a new file if it does not
    DELETE_ON_CLOSEDeletes the file when the stream is closed; used most often for temporary files that exist only for the duration of the program
    Figure shows an application that writes a String of bytes to a file. The only differences from the preceding ScreenOut class are: • Additional import statements are used. • The class name is changed. • A Path is declared for a Grades.txt file. • Instead of assigning System.out to the OutputStream reference, a BufferedOutputStream object is assigned.
    import java.nio.file.*; import java.io.*; import static java.nio.file.StandardOpenOption.*; // Additional import statements are needed. public class FileOut // Class name is changed. { public static void main(String[] args) { Path file = // Path for file is declared. Paths.get("C:\\Java\\Chapter.13\\Grades.txt"); String s = "ABCDF"; byte[] data = s.getBytes(); OutputStream output = null; try { output = new BufferedOutputStream(Files.newOutputStream(file, CREATE)); output.write(data); output.flush(); output.close(); } catch(Exception e) { System.out.println("Message: " + e); } } }
    Reading from a File
    You use an InputStream like you use an OutputStream. If you want, you can create an InputStream, assign System.in to it, and use the class’s read() method with the created object to retrieve keyboard input. Usually, however, it is more efficient to use the Scanner class for keyboard input and to use the InputStream class to input data that has been stored in a file. To open a file for reading, you can use the Files class newInputStream() method. This method accepts a Path parameter and returns a stream that can read bytes from a file. Figure shows a ReadFile class that reads from the Grades.txt file created earlier. The Path is declared, an InputStream is declared using the Path, and a stream is assigned to the InputStream reference.
    import java.nio.file.*; import java.io.*; public class ReadFile { public static void main(String[] args) { Path file = Paths.get("C:\\Java\\Chapter.13\\Grades.txt"); InputStream input = null; try { input = Files.newInputStream(file); BufferedReader reader = new BufferedReader(new InputStreamReader(input)); String s = null; s = reader.readLine(); System.out.println(s); input.close(); } catch (IOException e) { System.out.println(e); } } }
    The ReadFile class declares a BufferedReader object. A BufferedReader reads a line of text from a character-input stream, buffering characters so that reading is more efficient. When the ReadFile program executes, the readLine() method gets the single line of text from the Grades.txt file, and then the line, ABCDF, is displayed. When you use the BufferedReader class, you must import the java.io package into your program. Table shows some useful BufferedReader methods.
    BufferedReader MethodDescription
    close()Closes the stream and any resources associated with it
    read()Reads a single character
    read(char[] buffer, int off, int len)Reads characters into a portion of an array from position off for len characters
    readLine()Reads a line of text
    skip(long n)Skips the specified number of characters
  5. Creating and Using Sequential Data Files

    Frequently, you want to save more than a single String to a file. For example, you might have a data file of personnel records that include an ID number, name, and pay rate for each employee in your organization. Figure shows a program that reads employee ID numbers, names, and pay rates from the keyboard and sends them to a comma-separated file.
    import java.nio.file.*; import java.io.*; import static java.nio.file.StandardOpenOption.*; import java.util.Scanner; public class WriteEmployeeFile { public static void main(String[] args) { Scanner input = new Scanner(System.in); Path file = Paths.get("C:\\Java\\Chapter.13\\Employees.txt"); String s = ""; String delimiter = ","; int id; String name; double payRate; final int QUIT = 999; try { OutputStream output = new BufferedOutputStream(Files.newOutputStream(file, CREATE)); BufferedWriter writer = new // BufferedWriter object is declared. BufferedWriter(new OutputStreamWriter(output)); System.out.print("Enter employee ID number >> "); id = input.nextInt(); while(id != QUIT) { System.out.print("Enter name for employee #" + id + " >> "); input.nextLine(); name = input.nextLine(); System.out.print("Enter pay rate >> "); payRate = input.nextDouble(); s = id + delimiter + name + delimiter + payRate; writer.write(s, 0, s.length()); // BufferedWriter object uses write() method. writer.newLine(); System.out.print("Enter next ID number or " + QUIT + " to quit >> "); id = input.nextInt(); } writer.close(); } catch(Exception e) { System.out.println("Message: " + e); } } }
    Table contains all the methods defined in the BufferedWriter class.
    BufferedWriter MethodDescription
    close()Closes the stream, flushing it first
    flush()Flushes the stream
    newline()Writes a line separator
    write(String s, int off, int len)Writes a String from position off for length len
    write(char[] array, int off, int len)Writes a character array from position off for length len
    write(int c)Writes a single character
    Figure shows a program that reads the Employees.txt file created by the WriteEmployeeFile program. The program declares an InputStream for the file, then creates a BufferedReader using the InputStream. The first line is read into a String; as long as the readLine() method does not return null, the String is displayed and a new line is read.
    import java.nio.file.*; import java.io.*; public class ReadEmployeeFile { public static void main(String[] args) { Path file = Paths.get("C:\\Java\\Chapter.13\\Employees.txt"); String s = ""; try { InputStream input = new BufferedInputStream(Files.newInputStream(file)); BufferedReader reader = new BufferedReader(new InputStreamReader(input)); s = reader.readLine(); while(s != null) { System.out.println(s); s = reader.readLine(); } reader.close(); } catch(Exception e) { System.out.println("Message: " + e); } } }
    Many applications would not want to use the file data only as a String like the ReadEmployeeFile program does. Figure shows a more useful program in which the retrieved file Strings are split into usable fields. The String class split() method accepts an argument that identifies the field delimiter (in this case, a comma) and returns an array of Strings. Each array element holds one field. Then methods such as parseInt() and parseDouble() can be used to reformat the split Strings into their respective data types
    import java.nio.file.*; import java.io.*; public class ReadEmployeeFile2 { public static void main(String[] args) { Path file = Paths.get("C:\\Java\\Chapter.13\\Employees.txt"); String[] array = new String[3]; String s = ""; String delimiter = ","; int id; String name; double payRate; double gross; final double HRS_IN_WEEK = 40; double total = 0; try { InputStream input = new BufferedInputStream(Files.newInputStream(file)); BufferedReader reader = new BufferedReader(new InputStreamReader(input)); System.out.println(); s = reader.readLine(); while(s != null) { array = s.split(delimiter); id = Integer.parseInt(array[0]); name = array[1]; payRate = Double.parseDouble(array[2]); gross = payRate * HRS_IN_WEEK; System.out.println("ID#" + id + " " + name + " $" + payRate + " $" + gross); total += gross; s = reader.readLine(); } reader.close(); } catch(Exception e) { System.out.println("Message: " + e); } System.out.println(" Total gross payroll is $" + total); } }
  6. Learning About Random Access Files

    The file examples in the first part of this chapter have been sequential access files, which means that you work with the records in sequential order from beginning to end. For example, in the ReadEmployeeFile programs, if you write an employee record with an ID number of 145, and then write a second record with an ID number of 289, the records remain in the original data-entry order when you retrieve them. Businesses store data in sequential order when they use the records for batch processing, which involves performing the same tasks with many records, one after the other. For example, when a company produces customer bills, the records for the billing period are gathered in a batch and the bills are calculated and printed in sequence. It really doesn’t matter whose bill is produced first because no bills are distributed to customers until all bills in a group or batch have been printed and mailed. For many applications, sequential access is inefficient. These applications, known as real-time applications, require that a record be accessed immediately while a client is waiting. A program in which the user makes direct requests is an interactive program. For example, if a customer telephones a department store with a question about a monthly bill, the customer service representative does not want to access every customer account in sequence. Suppose that the store’s database contains tens of thousands of account records to read, and that the customer record in question is near the end of the list. It would take too long to access the customer’s record if all the records had to be read sequentially. Instead, customer service representatives require random access files—files in which records can be retrieved directly in any order. Random files are also called direct access files or instant access files. You can use Java’s FileChannel class to create your own random access files. A file channel object is an avenue for reading and writing a file. A file channel is seekable, meaning you can search for a specific file location and operations can start at any specified position. Table describes some FileChannel methods.
    FileChannel MethodDescription
    FileChannel open(Path file, OpenOption... options)Opens or creates a file, returning a file channel to access the file
    long position()Returns the channel’s file position
    FileChannel position(long newPosition)Sets the channel’s file position
    int read(ByteBuffer buffer)Reads a sequence of bytes from the channel into the buffer
    long size()Returns the size of the channel’s file
    int write(ByteBuffer buffer)Writes a sequence of bytes to the channel from the buffer
    Creating a usable FileChannel for randomly writing data requires creating a ByteBuffer and several other steps: • You can use the Files class newByteChannel() method to get a ByteChannel for a Path. The newByteChannel() method accepts Path and StandardOpenOption arguments that specify how the file will be opened. • The ByteChannel returned by the newByteChannel() method then can be cast to a FileChannel using a statement similar to the following: FileChannel fc = (FileChannel)Files.newByteChannel(file, READ, WRITE); • You can create a byte array. For example, a byte array can be built from a String using the getBytes() method as follows: String s = "XYZ"; byte[] data = s.getBytes(); • The byte array can be wrapped into a ByteBuffer as follows: ByteBuffer out = ByteBuffer.wrap(data); • Then the filled ByteBuffer can be written to the declared FileChannel with a statement such as the following: fc.write(out); • You can test whether a ByteBuffer’s contents have been used up by checking the hasRemaining() method. • After you have written the contents of a ByteBuffer, you can write the same ByteBuffer contents again by using the rewind() method to reposition the ByteBuffer to the beginning of the buffer. Figure employs all these steps to declare a file and write some bytes in it randomly at positions 0, 22, and 12, in that order.
    import java.nio.file.*; import java.io.*; import java.nio.channels.FileChannel; import java.nio.ByteBuffer; import static java.nio.file.StandardOpenOption.*; public class RandomAccessTest { public static void main(String[] args) { Path file = Paths.get("C:\\Java\\Chapter.13\\Numbers.txt"); String s = "XYZ"; byte[] data = s.getBytes(); ByteBuffer out = ByteBuffer.wrap(data); FileChannel fc = null; try { fc = (FileChannel)Files.newByteChannel(file, READ, WRITE); fc.position(0); while(out.hasRemaining()) fc.write(out); out.rewind(); fc.position(22); while(out.hasRemaining()) fc.write(out); out.rewind(); fc.position(12); while(out.hasRemaining()) fc.write(out); fc.close(); } catch (Exception e) { System.out.println("Error message: " + e); } } }
  7. Writing Records to a Random Access Data File

    Writing characters at random text file locations, as in the RandomAccessTest program, is of limited value. When you store records in a file, it is often more useful to be able to access the eighth or twelfth record rather than the eighth or twelfth byte. In such a case, you multiply each record’s size by the position you want to access. For example, if you store records that are 50 bytes long, the first record is at position 0, the second record is at position 50, the third record is at position 100, and so on. In other words, you can access the nth record in a FileChannel named fc using the following statement: fc.position((n - 1) * 50); One approach to writing a random access file is to place records into the file based on a key field. A key field is the field in a record that makes the record unique from all others. For example, suppose you want to store employee ID numbers, last names, and pay rates in a random access file. In a file of employees, many records might have the same last name or pay rate, but each record has a unique employee ID number, so that field can act as the key field. The first step in creating the random access employee file is to create a file that holds default records—for example, using zeroes for the ID numbers and pay rates and blanks for the names. For this example, assume that each employee ID number is three digits; in other words, you cannot have more than 1,000 employees because the ID number cannot surpass 999. Figure contains a program that creates 1,000 such records.
    import java.nio.file.*; import java.io.*; import java.nio.ByteBuffer; import static java.nio.file.StandardOpenOption.*; public class CreateEmptyEmployeesFile { public static void main(String[] args) { Path file = Paths.get("C:\\Java\\Chapter.13\\RandomEmployees.txt"); String s = "000, ,00.00" + System.getProperty("line.separator"); // String that represents a default record byte[] data = s.getBytes(); ByteBuffer buffer = ByteBuffer.wrap(data); final int NUMRECS = 1000; try { OutputStream output = new BufferedOutputStream(Files.newOutputStream(file, CREATE)); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output)); for(int count = 0; count < NUMRECS; ++count) // Loop that writes 1,000 default records writer.write(s, 0, s.length()); writer.close(); } catch(Exception e) { System.out.println("Error message: " + e); } } }
    For example, the application in Figure creates a single employee record. The record is for employee 002 with a last name of Newmann and a pay rate of 12.25. The length of this string is assigned to RECSIZE. (In this case, RECSIZE is 19, which includes one character for each character in the sample record string, including the delimiting commas, plus two bytes for the line separator value returned by the System.getProperty() method.) After the FileChannel is established, the record is written to the file at the position that begins at two times the record size. The value 2 is hard coded in this demonstration program because the employee’s ID number is 002.
    import java.nio.file.*; import java.io.*; import java.nio.channels.FileChannel; import java.nio.ByteBuffer; import static java.nio.file.StandardOpenOption.*; public class CreateOneRandomAccessRecord { public static void main(String[] args) { Path file = Paths.get("C:\\Java\\Chapter.13\\RandomEmployees.txt"); String s = "002,Newmann,12.25" + System.getProperty("line.separator"); final int RECSIZE = s.length(); byte[] data = s.getBytes(); ByteBuffer buffer = ByteBuffer.wrap(data); FileChannel fc = null; try { fc = (FileChannel)Files.newByteChannel(file, READ, WRITE); fc.position(2 * RECSIZE); // Because employee number is 2, position is set to 2 times the size of each record. fc.write(buffer); fc.close(); } catch (Exception e) { System.out.println("Error message: " + e); } } }
    A program that inserts one hard-coded employee record into a data file is not very useful. The program in Figure accepts any number of records as user input and writes records to a file in a loop. Each employee’s data value is accepted from the keyboard as a String and converted to an integer using the parseInt() method. Then, the record’s desired position is computed by multiplying the ID number value by the record size.
    import java.nio.file.*; import java.io.*; import java.nio.channels.FileChannel; import java.nio.ByteBuffer; import static java.nio.file.StandardOpenOption.*; import java.util.Scanner; public class CreateEmployeesRandomFile { public static void main(String[] args) { Scanner input = new Scanner(System.in); Path file = Paths.get("C:\\Java\\Chapter.13\\RandomEmployees.txt"); String s = "000, ,00.00” + System.getProperty("line.separator"); final int RECSIZE = s.length(); FileChannel fc = null; String delimiter = ","; String idString; int id; String name; String payRate; final String QUIT = "999"; try { fc = (FileChannel)Files.newByteChannel(file, READ, WRITE); System.out.print("Enter employee ID number >> "); idString = input.nextLine(); while(!(idString.equals(QUIT))) { id = Integer.parseInt(idString); // The employee’s ID number will be used to determine the record’s position. System.out.print("Enter name for employee #" + id + " >> "); name = input.nextLine(); System.out.print("Enter pay rate >> "); payRate = input.nextLine(); s = idString + delimiter + name + delimiter + payRate + System.getProperty("line.separator"); byte[] data = s.getBytes(); ByteBuffer buffer = ByteBuffer.wrap(data); fc.position(id * RECSIZE); // The position is the ID number value times the size of each record. fc.write(buffer); System.out.print("Enter next ID number or " + QUIT + " to quit >> "); idString = input.nextLine(); } fc.close(); } catch (Exception e) { System.out.println("Error message: " + e); } } }
  8. Reading Records from a Random Access Data File

    Accessing a Random Access File Sequentially
    The RandomEmployees.txt file created in the previous section contains 1,000 records, but only four of them contain valuable data. Displaying every record in the file would result in many irrelevant lines of output. It makes more sense to display only those records for which an ID number has been inserted. The application in Figure reads through the 1,000-record file sequentially in a while loop. The if statement checks for valid, non-zero ID numbers. If 000 could be a valid ID number, then you would want to check for a name that was blank, a pay rate that was 0, or both.
    import java.nio.file.*; import java.io.*; import static java.nio.file.AccessMode.*; public class ReadEmployeesSequentially { public static void main(String[] args) { Path file = Paths.get("C:\\Java\\Chapter.13\\RandomEmployees.txt"); String[] array = new String[3]; String s = ""; String delimiter = ","; int id; String stringId; String name; double payRate; double gross; final double HRS_IN_WEEK = 40; double total = 0; try { InputStream input = new BufferedInputStream(Files.newInputStream(file)); BufferedReader reader = new BufferedReader(new InputStreamReader(input)); System.out.println(); s = reader.readLine(); while(s != null) { array = s.split(delimiter); stringId = array[0]; id = Integer.parseInt(array[0]); if(id != 0) // Records are printed only if the ID number is not zero. { name = array[1]; payRate = Double.parseDouble(array[2]); gross = payRate * HRS_IN_WEEK; System.out.println("ID#" + stringId + " " + name + " $" + payRate + " $" + gross); total += gross; } s = reader.readLine(); } reader.close(); } catch(Exception e) { System.out.println("Message: " + e); } System.out.println(" Total gross payroll is $" + total); } }
    Accessing a Random Access File Randomly
    If you simply want to display records in order based on their key field, you do not need to create a random access file and waste unneeded storage. Instead, you could sort the records using one of the techniques you learned in Chapter 9. The benefit of using a random access file is the ability to retrieve a specific record from a file directly, without reading through other records to locate the desired one. In the ReadEmployeesRandomly application in previous Figure, the user is prompted for an employee ID number, which is converted to an integer with the parseInt() method. (To keep this example brief, the application does not check for a valid ID number, so the parseInt() method might throw an exception to the operating system, ending the execution of the application.) In the application in Figure, the position of the desired record is calculated by multiplying the ID number by the record size and then positioning the file pointer at the desired location. (Again, to keep the example short, the ID number is not checked to ensure that it is 999 or less.) The employee record is retrieved from the data file and displayed, and then the user is prompted for the next desired ID number. Figure shows a typical execution.
    import java.nio.file.*; import java.io.*; import java.nio.channels.FileChannel; import java.nio.ByteBuffer; import static java.nio.file.StandardOpenOption.*; import java.util.Scanner; public class ReadEmployeesRandomly { public static void main (String[] args) { Scanner keyBoard = new Scanner(System.in); Path file = Paths.get("C:\\Java\\Chapter.13\\RandomEmployees.txt"); Strings = "000, ,00.00" + System.getProperty("line.separator"); final int RECSIZE = s.length(); byte[] data = s.getBytes(); ByteBuffer buffer = ByteBuffer.wrap(data); FileChannel fc = null; String idString; int id; final String QUIT = "999"; try { fc = (FileChannel)Files.newByteChannel(file, READ, WRITE); System.out.print("Enter employee ID number or " + QUIT + " to quit >> "); idString = keyBoard.nextline(); while(!idString.equals(QUIT)) { id = Integer.parseInt(idString); buffer = ByteBuffer.wrap(data); fc.position(id * RECSIZE); fc.read(buffer); s = new String(data); System.out.println("ID #" + id + " " + s); System.out.print("Enter employee ID number or " + QUIT + " to quit >> "); idString = keyBoard.nextLine(); } fc.close(); } catch (Exception e) { System.out.println("Error message: " + e); } } }
    For example, the application in Figure creates a single employee record. The record is for employee 002 with a last name of Newmann and a pay rate of 12.25. The length of this string is assigned to RECSIZE. (In this case, RECSIZE is 19, which includes one character for each character in the sample record string, including the delimiting commas, plus two bytes for the line separator value returned by the System.getProperty() method.) After the FileChannel is established, the record is written to the file at the position that begins at two times the record size. The value 2 is hard coded in this demonstration program because the employee’s ID number is 002.
    import java.nio.file.*; import java.io.*; import java.nio.channels.FileChannel; import java.nio.ByteBuffer; import static java.nio.file.StandardOpenOption.*; public class CreateOneRandomAccessRecord { public static void main(String[] args) { Path file = Paths.get("C:\\Java\\Chapter.13\\RandomEmployees.txt"); String s = "002,Newmann,12.25" + System.getProperty("line.separator"); final int RECSIZE = s.length(); byte[] data = s.getBytes(); ByteBuffer buffer = ByteBuffer.wrap(data); FileChannel fc = null; try { fc = (FileChannel)Files.newByteChannel(file, READ, WRITE); fc.position(2 * RECSIZE); // Because employee number is 2, position is set to 2 times the size of each record. fc.write(buffer); fc.close(); } catch (Exception e) { System.out.println("Error message: " + e); } } }
    A program that inserts one hard-coded employee record into a data file is not very useful. The program in Figure accepts any number of records as user input and writes records to a file in a loop. Each employee’s data value is accepted from the keyboard as a String and converted to an integer using the parseInt() method. Then, the record’s desired position is computed by multiplying the ID number value by the record size.
    import java.nio.file.*; import java.io.*; import java.nio.channels.FileChannel; import java.nio.ByteBuffer; import static java.nio.file.StandardOpenOption.*; import java.util.Scanner; public class CreateEmployeesRandomFile { public static void main(String[] args) { Scanner input = new Scanner(System.in); Path file = Paths.get("C:\\Java\\Chapter.13\\RandomEmployees.txt"); String s = "000, ,00.00” + System.getProperty("line.separator"); final int RECSIZE = s.length(); FileChannel fc = null; String delimiter = ","; String idString; int id; String name; String payRate; final String QUIT = "999"; try { fc = (FileChannel)Files.newByteChannel(file, READ, WRITE); System.out.print("Enter employee ID number >> "); idString = input.nextLine(); while(!(idString.equals(QUIT))) { id = Integer.parseInt(idString); // The employee’s ID number will be used to determine the record’s position. System.out.print("Enter name for employee #" + id + " >> "); name = input.nextLine(); System.out.print("Enter pay rate >> "); payRate = input.nextLine(); s = idString + delimiter + name + delimiter + payRate + System.getProperty("line.separator"); byte[] data = s.getBytes(); ByteBuffer buffer = ByteBuffer.wrap(data); fc.position(id * RECSIZE); // The position is the ID number value times the size of each record. fc.write(buffer); System.out.print("Enter next ID number or " + QUIT + " to quit >> "); idString = input.nextLine(); } fc.close(); } catch (Exception e) { System.out.println("Error message: " + e); } } }
  9. You Do It Exercises

    import java.nio.file.*; import java.io.*; import java.nio.channels.FileChannel; import java.nio.ByteBuffer; import static java.nio.file.StandardOpenOption.*; import java.util.Scanner; import java.text.*; public class CreateFilesBasedOnState { public static void main(String[] args) { Scanner input = new Scanner(System.in); Path inStateFile = Paths.get("C:\\Java\\Chapter.13\\InStateCusts.txt"); Path outOfStateFile = Paths.get("C:\\Java\\Chapter.13\\OutOfStateCusts.txt"); final String ID_FORMAT = "000"; final String NAME_FORMAT = " "; final int NAME_LENGTH = NAME_FORMAT.length(); final String HOME_STATE = "WI"; final String BALANCE_FORMAT = "0000.00"; String delimiter = ","; String s = ID_FORMAT + delimiter + NAME_FORMAT + delimiter + HOME_STATE + delimiter + BALANCE_FORMAT + System.getProperty("line.separator"); final int RECSIZE = s.length(); FileChannel fcIn = null; FileChannel fcOut = null; String idString; int id; String name; String state; double balance; final String QUIT = "999"; createEmptyFile(inStateFile, s); createEmptyFile(outOfStateFile, s); try { fcIn = (FileChannel)Files.newByteChannel(inStateFile, CREATE, WRITE); fcOut = (FileChannel)Files.newByteChannel(outOfStateFile, CREATE, WRITE); System.out.print("Enter customer account number >> "); idString = input.nextLine(); while(!(idString.equals(QUIT))) { id = Integer.parseInt(idString); System.out.print("Enter name for customer >> "); name = input.nextLine(); StringBuilder sb = new StringBuilder(name); sb.setLength(NAME_LENGTH); name = sb.toString(); System.out.print("Enter state >> "); state = input.nextLine(); System.out.print("Enter balance >> "); balance = input.nextDouble(); input.nextLine(); DecimalFormat df = new DecimalFormat(BALANCE_FORMAT); s = idString + delimiter + name + delimiter + state + delimiter + df.format(balance) + System.getProperty("line.separator"); byte data[] = s.getBytes(); ByteBuffer buffer = ByteBuffer.wrap(data); if(state.equals(HOME_STATE)) { fcIn.position(id * RECSIZE); fcIn.write(buffer); } else { fcOut.position(id * RECSIZE); fcOut.write(buffer); } System.out.print("Enter next customer account number or " + QUIT + " to quit >> "); idString = input.nextLine(); } fcIn.close(); fcOut.close(); } catch (Exception e) { System.out.println("Error message: " + e); } } public static void createEmptyFile(Path file, String s) { final int NUMRECS = 1000; try { OutputStream outputStr = new BufferedOutputStream(Files.newOutputStream(file, CREATE)); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStr)); for(int count = 0; count < NUMRECS; ++count) writer.write(s, 0, s.length()); writer.close(); } catch(Exception e) { System.out.println("Error message: " + e); } } }
    import java.nio.file.*; import java.io.*; import java.nio.file.attribute.*; import static java.nio.file.StandardOpenOption.*; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.Scanner; public class ReadStateFile { public static void main(String[] args) { Scanner kb = new Scanner(System.in); String fileName; System.out.print("Enter name of file to use >> "); fileName = kb.nextLine(); fileName = "C:\\Java\\Chapter.13\\" + fileName; Path file = Paths.get(fileName); final String ID_FORMAT = "000"; final String NAME_FORMAT = " "; final int NAME_LENGTH = NAME_FORMAT.length(); final String HOME_STATE = "WI"; final String BALANCE_FORMAT = "0000.00"; String delimiter = ","; String s = ID_FORMAT + delimiter + NAME_FORMAT + delimiter + HOME_STATE + delimiter + BALANCE_FORMAT + System.getProperty("line.separator"); final int RECSIZE = s.length(); byte data[] = s.getBytes(); final String EMPTY_ACCT = "000"; String[] array = new String[4]; double balance; double total = 0; try { BasicFileAttributes attr = Files.readAttributes(file, BasicFileAttributes.class); System.out.println("\nAttributes of the file:"); System.out.println("Creation time " + attr.creationTime()); System.out.println("Size " + attr.size()); } catch(IOException e) { System.out.println("IO Exception"); } try { InputStream iStream = new BufferedInputStream(Files.newInputStream(file)); BufferedReader reader = new BufferedReader(new InputStreamReader(iStream)); System.out.println("\nAll non-default records:\n"); s = reader.readLine(); while(s != null) { array = s.split(delimiter); if(!array[0].equals(EMPTY_ACCT)) { balance = Double.parseDouble(array[3]); System.out.println("ID #" + array[0] + " " + array[1] + array[2] + " $" + array[3]); total += balance; } s = reader.readLine(); } System.out.println("Total of all balances is $" + total); reader.close(); } catch(Exception e) { System.out.println("Message: " + e); } try { FileChannel fc = (FileChannel)Files.newByteChannel(file, READ); ByteBuffer buffer = ByteBuffer.wrap(data); int findAcct; System.out.print("\nEnter account to seek >> "); findAcct = kb.nextInt(); fc.position(findAcct * RECSIZE); fc.read(buffer); s = new String(data); System.out.println("Desired record: " + s); } catch(Exception e) { System.out.println("Message: " + e); } } }
  10. Case Problems

    import java.nio.file.*; import java.io.*; import static java.nio.file.StandardOpenOption.*; import java.util.Scanner; import java.nio.channels.FileChannel; public class StaffDinnerEventAndCreateFile { public static void main(String[] args) { Employee[] emps = new Employee[15]; DinnerEvent[] events = new DinnerEvent[3]; int count; String eventNum; int guests; int option; int x; int y; int waitStaff; int bartenders; int[] menuOption = new int[4]; for(int es = 0; es < events.length; ++es) { eventNum = getEventNumber(); guests = getGuests(); for(y = 0; y < menuOption.length; ++y) menuOption[y] = getMenu(y); events[es] = new DinnerEvent(eventNum, guests, menuOption[0], menuOption[1], menuOption[2], menuOption[3]); events[es].setContactPhone(getPhone()); events[es].setEventType(getType()); waitStaff = guests / 10 + 1; for(count = 0; count < waitStaff; ++count) emps[count] = getWaitstaff(); bartenders = guests / 25 + 1; for(; count < waitStaff + bartenders; ++count) emps[count] = getBartender(); emps[count] = getCoordinator(); events[es].setEmps(emps); ++count; System.out.println("\n\nNow display the event"); displayDetails(events[es], count); } writeDataFile(events); } public static Waitstaff getWaitstaff() { Scanner in = new Scanner(System.in); Waitstaff ws= new Waitstaff(); System.out.print("Enter Employee number for waitstaff >> "); ws.setEmployeeNumber(in.nextLine()); System.out.print("Enter first name >> "); ws.setFirstName(in.nextLine()); System.out.print("Enter last name >> "); ws.setLastName(in.nextLine()); boolean isValidPayRate = false; while(!isValidPayRate) { isValidPayRate = true; try { System.out.print("Enter pay rate >> "); ws.setPayRate(in.nextDouble()); } catch(Exception e) { isValidPayRate = false; } in.nextLine(); } ws.setJobTitle(); return ws; } public static Bartender getBartender() { Scanner in = new Scanner(System.in); Bartender bt= new Bartender(); System.out.print("Enter Employee number for bartender >> "); bt.setEmployeeNumber(in.nextLine()); System.out.print("Enter first name >> "); bt.setFirstName(in.nextLine()); System.out.print("Enter last name >> "); bt.setLastName(in.nextLine()); boolean isValidPayRate = false; while(!isValidPayRate) { isValidPayRate = true; try { System.out.print("Enter pay rate >> "); bt.setPayRate(in.nextDouble()); } catch(Exception e) { isValidPayRate = false; } in.nextLine(); } bt.setJobTitle(); return bt; } public static Coordinator getCoordinator() { Scanner in = new Scanner(System.in); Coordinator co= new Coordinator(); System.out.print("Enter Employee number for coordinator >> "); co.setEmployeeNumber(in.nextLine()); System.out.print("Enter first name >> "); co.setFirstName(in.nextLine()); System.out.print("Enter last name >> "); co.setLastName(in.nextLine()); boolean isValidPayRate = false; while(!isValidPayRate) { isValidPayRate = true; try { System.out.print("Enter pay rate >> "); co.setPayRate(in.nextDouble()); } catch(Exception e) { isValidPayRate = false; } in.nextLine(); } co.setJobTitle(); return co; } public static String getEventNumber() { String num; Scanner input = new Scanner(System.in); System.out.print("\nEnter event number >> "); num = input.nextLine(); return num; } public static int getGuests() { int guests = 0; final int MIN_GUESTS = 5; final int MAX_GUESTS = 100; Scanner input = new Scanner(System.in); boolean isGuestsOK = false; while(!isGuestsOK) { isGuestsOK = true; try { System.out.print("Enter number of guests >> "); guests = input.nextInt(); } catch(Exception e) { isGuestsOK = false; } input.nextLine(); } while(guests < MIN_GUESTS || guests > MAX_GUESTS) { System.out.println("The number of guests must be between " + MIN_GUESTS + " and " + MAX_GUESTS); isGuestsOK = false; while(!isGuestsOK) { isGuestsOK = true; try { System.out.print("Please renter >> "); guests = input.nextInt(); } catch(Exception e) { isGuestsOK = false; } input.nextLine(); } } return guests; } public static int getType() { int eType = 0; Scanner input = new Scanner(System.in); System.out.println("Event types are"); for(int x = 0; x < Event.EVENT_TYPES.length; ++x) System.out.println(" " + x + " " + Event.EVENT_TYPES[x]); boolean isTypeOK = false; while(!isTypeOK) { isTypeOK = true; try { System.out.print("Enter event type >> "); eType = input.nextInt(); } catch(Exception e) { isTypeOK = false; } input.nextLine(); } return eType; } public static void writeDataFile(DinnerEvent[] e) { String s; String delimiter = ","; OutputStream ostream; BufferedWriter writer; Path file = Paths.get("C:\\Java\\Chapter.13\\Events.txt"); try { ostream = new BufferedOutputStream(Files.newOutputStream(file, CREATE)); writer = new BufferedWriter(new OutputStreamWriter(ostream)); for(int x = 0; x < e.length; ++x) { s = e[x].getEventNumber() + delimiter + e[x].getEventType() + delimiter + e[x].getGuests() + delimiter + e[x].getPriceForEvent() + System.getProperty("line.separator"); writer.write(s, 0, s.length()); } writer.close(); } catch(Exception x) { System.out.println("Message: " + x); } } public static void displayDetails(DinnerEvent e, int count) { Employee[] emps = new Employee[15]; emps = e.getEmps(); System.out.println("\nEvent #" + e.getEventNumber()); System.out.println("The price for an event with " + e.getGuests() + " guests at $" + e.getPricePerGuest() + " per guest is $" + e.getPriceForEvent()); System.out.println("Whether this is a large event is " + (e.getGuests() >= e.LARGE_EVENT)); System.out.println("Contact phone number is: " + e.getContactPhone()); System.out.println("The event is type " + e.getEventType() + " which is the following type: " + e.getEventTypeString()); System.out.println("The menu includes " + e.getMenu()); System.out.println("\nThe staff includes:"); for(int x = 0; x < count; ++x) { System.out.print(emps[x].getEmployeeNumber()); System.out.print( " " + emps[x].getName()); System.out.println( " " + emps[x].getPayRate() + " " + emps[x].getJobTitle()); } } public static DinnerEvent getLarger(DinnerEvent e1, DinnerEvent e2) { DinnerEvent larger = e2; if(e1.getGuests() >= e2.getGuests()) larger = e1; return larger; } public static String getPhone() { String phone; Scanner input = new Scanner(System.in); System.out.print("Enter contact phone number >> "); phone = input.nextLine(); return phone; } public static int getMenu(int y) { int choice; if(y == 0) choice = displayEntreeMenu(); else if (y == 1 || y == 2) choice = displaySidesMenu(); else choice = displayDessertMenu(); return choice; } public static int displayEntreeMenu() { Scanner keyboard = new Scanner(System.in); int x; int choice = 0; boolean isEntreeOK = false; while(!isEntreeOK) { isEntreeOK = true; try { System.out.println("Please select from the following entrees:"); for(x = 0; x < DinnerEvent.ENTREES.length; ++x) System.out.println(x + " -- " + DinnerEvent.ENTREES[x]); System.out.print(" >> "); choice = keyboard.nextInt(); } catch(Exception e) { isEntreeOK = false; } keyboard.nextLine(); } return choice; } public static int displaySidesMenu() { Scanner keyboard = new Scanner(System.in); int x; int choice = 0; boolean isSidesOK = false; while(!isSidesOK) { isSidesOK = true; try { System.out.println("Please select from the following sides:"); for(x = 0; x < DinnerEvent.SIDES.length; ++x) System.out.println(x + " -- " + DinnerEvent.SIDES[x]); System.out.print(" >> "); choice = keyboard.nextInt(); } catch(Exception e) { isSidesOK = false; } keyboard.nextLine(); } return choice; } public static int displayDessertMenu() { Scanner keyboard = new Scanner(System.in); int x; int choice = 0; boolean isDessertOK = false; while(!isDessertOK) { isDessertOK = true; try { System.out.println("Please select from the following desserts:"); for(x = 0; x < DinnerEvent.DESSERTS.length; ++x) System.out.println(x + " -- " + DinnerEvent.DESSERTS[x]); System.out.print(" >> "); choice = keyboard.nextInt(); } catch(Exception e) { isDessertOK = false; } keyboard.nextLine(); } return choice; } }
    import java.nio.file.*; import java.io.*; import static java.nio.file.StandardOpenOption.*; public class DisplayDinnerEventFile { public static void main(String[] args) { Path deFile = Paths.get("C:\\Java\\Chapter.13\\Events.txt"); String s = ""; try { InputStream dinner = new BufferedInputStream(Files.newInputStream(deFile)); BufferedReader dinnerReader = new BufferedReader(new InputStreamReader(dinner)); System.out.println("\nDinner Events\n"); System.out.println("ID # Type Guests Price"); s = dinnerReader.readLine(); while( s != null) { display(s); s = dinnerReader.readLine(); } dinnerReader.close(); } catch(Exception e) { System.out.println("Message: " + e); } } public static void display(String s) { String[] array = new String[4]; String delimiter = ","; String stringId; String eventType; int guests; double price; array = s.split(delimiter); stringId = array[0]; eventType = array[1]; guests = Integer.parseInt(array[2]); price = Double.parseDouble(array[3]); System.out.println(stringId + " " + eventType + " " + guests + " $" + price); } }
    import java.nio.file.*; import java.io.*; import static java.nio.file.StandardOpenOption.*; import java.util.Scanner; import java.nio.channels.FileChannel; public class RentalDemoAndCreateFile { public static void main(String[] args) { int option; String contractNum; int minutes; final int QUIT = 9; int eType; Rental[] rentals = new Rental[4]; int x; for(x = 0; x < rentals.length; ++x) { contractNum = getContractNumber(); minutes = getMinutes(); eType = getType(); rentals[x] = new Rental(contractNum, minutes, eType); rentals[x].setContactPhone(getPhone()); } System.out.println("\n\nNow display the rentals"); for(x = 0; x < rentals.length; ++x) { displayDetails(rentals[x]); } writeFile(rentals); } public static String getContractNumber() { Scanner input = new Scanner(System.in); String num; System.out.print("\nEnter contract number >> "); num = input.nextLine(); return num; } public static int getMinutes() { int minutes = 0; final int LOW_MIN = 60; final int HIGH_MIN = 7200; Scanner input = new Scanner(System.in); boolean isOK = false; while(!isOK) { isOK = true; try { System.out.print("Enter minutes >> "); minutes = input.nextInt(); } catch(Exception e) { isOK = false; } input.nextLine(); } while(minutes < LOW_MIN || minutes > HIGH_MIN) { System.out.println("Time must be between " + LOW_MIN + " minutes and " + HIGH_MIN + " minutes"); isOK = false; while(!isOK) { isOK = true; try { System.out.print("Please reenter minutes >> "); minutes = input.nextInt(); } catch(Exception e) { isOK = false; } input.nextLine(); } } return minutes; } public static int getType() { int eType = 0; Scanner input = new Scanner(System.in); System.out.println("Equipment types:"); for(int x = 0; x < Equipment.EQUIP_TYPES.length; ++x) System.out.println(" " + x + " " + Equipment.EQUIP_TYPES[x]); boolean isOK = false; while(!isOK) { isOK = true; try { System.out.print("Enter equipment type >> "); eType = input.nextInt(); } catch(Exception e) { isOK = false; } input.nextLine(); } return eType; } public static void displayDetails(Rental r) { Equipment e = r.getEquipment(); System.out.println("\nContract #" + r.getContractNumber()); System.out.println("For a rental of " + r.getHours() + " hours and " + r.getExtraMinutes() + " minutes,\n at a rate of $" + r.HOUR_RATE + " per hour and $1 per extra minute,\n the base price is $" + r.getBasePrice()); System.out.println("Contact phone number is: " + r.getContactPhone()); System.out.println("Equipment rented is type #" + e.getEquipType() + " -- " + e.getEquipName()); System.out.println(e.getLessonMessage()); System.out.println("The equipment fee with lesson is " + e.getFee()); System.out.println("The total price is " + r.getPrice()); System.out.println("-------------------------------"); } public static String getPhone() { String phone; Scanner input = new Scanner(System.in); System.out.print("Enter contact phone number >> "); phone = input.nextLine(); return phone; } public static void writeFile(Rental[] r) { String s; String delimiter = ","; OutputStream ostream; BufferedWriter writer; Path file = Paths.get("C:\\Java\\Chapter.13\\Rentals.txt"); try { ostream = new BufferedOutputStream(Files.newOutputStream(file, CREATE)); writer = new BufferedWriter(new OutputStreamWriter(ostream)); for(int x = 0; x < r.length; ++x) { Equipment e = r[x].getEquipment(); s = r[x].getContractNumber() + delimiter + r[x].getHours() + delimiter + r[x].getExtraMinutes() + delimiter + e.getEquipType() + delimiter + e.getEquipName() + delimiter + r[x].getPrice() + System.getProperty("line.separator"); writer.write(s, 0, s.length()); } writer.close(); } catch(Exception x) { System.out.println("Message: " + x); } } }
    import java.nio.file.*; import java.io.*; import static java.nio.file.StandardOpenOption.*; public class DisplayRentalFile { public static void main(String[] args) { Path rFile = Paths.get("C:\\Java\\Chapter.13\\Rentals.txt"); String s = ""; try { InputStream rental = new BufferedInputStream(Files.newInputStream(rFile)); BufferedReader rentalReader = new BufferedReader(new InputStreamReader(rental)); System.out.println("\nRentaks\n"); s = rentalReader.readLine(); while( s != null) { display(s); s = rentalReader.readLine(); } rentalReader.close(); } catch(Exception e) { System.out.println("Message: " + e); } } public static void display(String s) { String[] array = new String[6]; String delimiter = ","; String stringId; String equip; int hours; int minutes; int equipType; double price; array = s.split(delimiter); stringId = array[0]; hours = Integer.parseInt(array[1]); minutes = Integer.parseInt(array[2]); equipType = Integer.parseInt(array[3]); equip = (array[4]); price = Double.parseDouble(array[5]); System.out.println("#" + stringId + " " + hours + " hours and " + minutes + " minutes Equipment: " + equipType + " " + equip + " Price $" + price); } }