C# imposes no structure on files. Thus, the concept of a "record" does not exist in C# files. This means that you must structure files to meet the requirements of your applications. In the next few examples, we use text and special characters to organize our own concept of a "record."
Class BankUIForm
The following examples demonstrate file processing in a bank-account maintenance application. These programs have similar user interfaces, so we created reusable class BankUIForm (Fig. 18.7 from the Visual Studio Form designer) to encapsulate a base-class GUI (see the screen capture in Fig. 18.7). Class BankUIForm contains four Labels and four TextBoxes. Methods ClearTextBoxes (lines 2640), SetTextBoxValues (lines 4361) and GetTextBoxValues (lines 6475) clear, set the values of and get the values of the text in the TextBoxes, respectively.
Figure 18.7. Base class for GUIs in our file-processing applications.
To reuse class BankUIForm, you must compile the GUI into a DLL by creating a project of type Windows Control Library (we named it BankLibrary). This library is provided with the code for this chapter. You might need to change references to this library in our examples when you copy them to your system, since the library most likely will reside in a different location on your system.
Class Record
Figure 18.8 contains class Record that Fig. 18.9, Fig. 18.11 and Fig. 18.12 use for maintaining the information in each record that is written to or read from a file. This class also belongs to the BankLibrary DLL, so it is located in the same project as class BankUIForm.
Figure 18.8. Record for sequential-access file-processing applications.
(This item is displayed on pages 894 - 895 in the print version)
Figure 18.9. Creating and writing to a sequential-access file.
(This item is displayed on pages 896 - 900 in the print version)
Figure 18.11. Reading sequential-access files.
(This item is displayed on pages 902 - 905 in the print version)
Figure 18.12. Credit-inquiry program.
(This item is displayed on pages 907 - 911 in the print version)
Class Record contains private instance variables account, firstName, lastName and balance (lines 912), which collectively represent all the information for a record. The parameterless constructor (lines 1517) sets these members by calling the four-argument constructor with 0 for the account number, empty strings ("") for the first and last name and 0.0M for the balance. The four-argument constructor (lines 2027) sets these members to the specified parameter values. Class Record also provides properties Account (lines 3040), FirstName (lines 4353), LastName (lines 5666) and Balance (lines 6979) for accessing each record's account number, first name, last name and balance, respectively.
Using a Character Stream to Create an Output File
Class CreateFileForm (Fig. 18.9) uses instances of class Record to create a sequential-access file that might be used in an accounts receivable systemi.e., a program that organizes data regarding money owed by a company's credit clients. For each client, the program obtains an account number and the client's first name, last name and balance (i.e., the amount of money that the client owes to the company for previously received goods and services). The data obtained for each client constitutes a record for that client. In this application, the account number is used as the record keyfiles are created and maintained in account-number order. This program assumes that the user enters records in account-number order. However, a comprehensive accounts receivable system would provide a sorting capability, so the user could enter the records in any order.
Class CreateFileForm either creates or opens a file (depending on whether one exists), then allows the user to write records to that file. The using directive in line 6 enables us to use the classes of the BankLibrary namespace; this namespace contains class BankUIForm, from which class CreateFileForm inherits (line 8). Class CreateFileForm's GUI enhances that of class BankUIForm with buttons Save As, Enter and Exit.
When the user clicks the Save As button, the program invokes the event handler saveButton_Click (lines 2063). Line 23 instantiates an object of class SaveFileDialog (namespace System.Windows.Forms). Objects of this class are used for selecting files (see the second screen in Fig. 18.9). Line 24 calls SaveFileDialog method ShowDialog to display the dialog. When displayed, a SaveFileDialog prevents the user from interacting with any other window in the program until the user closes the SaveFileDialog by clicking either Save or Cancel. Dialogs that behave in this manner are called modal dialogs. The user selects the appropriate drive, directory and file name, then clicks Save. Method ShowDialog returns a DialogResult specifying which button (Save or Cancel) the user clicked to close the dialog. This is assigned to DialogResult variable result (line 24). Line 30 tests whether the user clicked Cancel by comparing this value to DialogResult.Cancel. If the values are equal, method saveButton_Click returns (line 31). Otherwise, line 33 uses SaveFileDialog property FileName to obtain the user-selected file.
You can open files to perform text manipulation by creating objects of class FileStream. In this example, we want the file to be opened for output, so lines 4546 create a FileStream object. The FileStream constructor that we use receives three argumentsa string containing the path and name of the file to open, a constant describing how to open the file and a constant describing the file permissions. The constant FileMode.OpenOrCreate (line 46) indicates that the FileStream object should open the file if the file exists or create the file if it does not exist. There are other FileMode constants describing how to open files; we introduce these constants as we use them in examples. The constant FileAccess.Write indicates that the program can perform only write operations with the FileStream object. There are two other constants for the third constructor parameterFileAccess.Read for read-only access and FileAccess.ReadWrite for both read and write access. Line 56 catches an IOException if there is a problem opening the file or creating the StreamWriter. If so, the program displays an error message (lines 5960). If no exception occurs, the file is open for writing.
After the user types information in each TextBox, the user clicks the Enter button, which calls event handler enterButton_Click (lines 66121) to save the data from the TextBoxes into the user-specified file. If the user entered a valid account number (i.e., an integer greater than zero), lines 8892 store the TextBox values in an object of type Record (created at line 72). If the user entered invalid data in one of the TextBoxes (such as non-numeric characters in the Balance field), the program throws a FormatException. The catch block in lines 113117 handles such exceptions by notifying the user (via a MessageBox) of the improper format.
If the user entered valid data, lines 9597 write the record to the file by invoking method WriteLine of the StreamWriter object that was created at line 49. Method WriteLine writes a sequence of characters to a file. The StreamWriter object is constructed with a FileStream argument that specifies the file to which the StreamWriter will output text. Class StreamWriter belongs to the System.IO namespace.
When the user clicks the Exit button, event handler exitButton_Click (lines 124143) exits the application. Line 131 closes the StreamWriter, and line 132 closes the FileStream, then line 142 terminates the program. Note that the call to method Close is located in a TRy block. Method Close throws an IOException if the file or stream cannot be closed properly. In this case, it is important to notify the user that the information in the file or stream might be corrupted.
In the sample execution for the program in Fig. 18.9, we entered information for the five accounts shown in Fig. 18.10. The program does not depict how the data records are rendered in the file. To verify that the file has been created successfully, we create a program in the next section to read and display the file. Since this is a text file, you can actually open the file in any text editor to see its