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 apps. The next few examples use text and special characters to organize our own concept of a “record.”
BankUIForm
The following examples demonstrate file processing in a bank-account maintenance app. These programs have similar user interfaces, so we created reusable class BankUIForm
(Fig. 17.2) to encapsulate the common GUI (see the screen capture in Fig. 17.2). Class BankUIForm
(part of the BankLibrary
project with this chapter’s examples) contains four Label
s and four TextBox
es. Methods ClearTextBoxes
(lines 22–30), SetTextBoxValues
(lines 33–51) and GetTextBoxValues
(lines 54–59) clear, set the text in and get the text from the TextBox
es, respectively. Using visual inheritance—presented in Section 15.13— you can extend this class to create the GUIs for several examples in this chapter. Recall that to reuse class BankUIForm
, you must compile the GUI into a class library, then add a reference to the new class library’s DLL in each project that will reuse it (see Section 15.13).
Record
Figure 17.3 contains class Record
that Figs. 17.4, 17.6 and 17.7 use for maintaining the information in each record that’s written to or read from a file. This class also belongs to the BankLibrary
, so it’s located in the same project as class BankUIForm
.
Class Record
contains auto-implemented properties Account
, FirstName
, LastName
and Balance
(lines 7–10), which collectively represent all the information for a record. The parameterless constructor (line 13) sets these members by calling the four-argument constructor with 0
for the account number, string.Empty
for the first and last name and 0.0M
for the balance. The four-argument constructor (lines 16–23) sets these members to the specified parameter values.
Class CreateFileForm
(Fig. 17.4) uses instances of class Record
to create a sequential-access file that might be used in an accounts-receivable system—i.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 app, the account number is used as the record key—files 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. When you create a Windows Forms Application project for this app, be sure to add a reference to BankLibrary.dll
and to change the base class from Form
to BankUIForm
. See Section 15.13 for information on adding a reference to a class library.
Class CreateFileForm
either creates or opens a file (depending on whether one exists), then allows the user to write records to it. The using
directive in line 6 enables us to use the classes of the BankLibrary
namespace; this namespace contains class BankUI-Form
, from which class CreateFileForm
inherits (line 10). Class CreateFileForm
’s GUI enhances that of class BankUIForm
with buttons Save As, Enter and Exit.
saveButton_Click
When the user clicks the Save As button, the program invokes the event handler saveButton_Click
(lines 21–67). Line 27 instantiates an object of class SaveFileDialog
(namespace System.Windows.Forms
). By placing this object in a using
statement (lines 27–32), we ensure that the dialog’s Dispose
method is called to release its resources as soon as the program has retrieved the user’s input. SaveFileDialog
objects are used for selecting files (see the second screen in Fig. 17.4). Line 29 indicates that the dialog should not check if the filename specified by the user already exists (this is actually the default). Line 30 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 filename, 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 30). Line 31 gets the filename from the dialog. Line 35 tests whether the user clicked OK by comparing this value to DialogResult.OK
. If the values are equal, method saveButton_Click
continues.
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 49–50 create a FileStream
object. The FileStream
constructor that we use receives three arguments—a 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 read-write permissions. The constant FileMode.OpenOrCreate
(line 50) indicates that the FileStream
object should open the file if it exists or create the file if it does not exist.
Note that the contents of an existing file are overwritten by the FileStream
. To preserve the original contents of a file, use FileMode.Append
. 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 parameter—FileAccess.Read
for read-only access and FileAccess.Read-Write
for both read and write access.
Line 59 catches an IOException
if there’s a problem opening the file or creating the StreamWriter
. If so, the program displays an error message (lines 62–63). If no exception occurs, the file is open for writing.
Failure to open a file before attempting to use it in a program is a logic error.
enterButton_Click
After typing information into each TextBox
, the user clicks Enter, which calls enter-Button_Click
(lines 70–119) to save the data from the TextBox
es into the user-specified file. If the user entered a valid account number (i.e., an integer greater than zero), lines 89– 92 create a Record
containing the TextBox
values. If the user entered invalid data in one of the TextBox
es (such as nonnumeric characters in the Balance field), the program throws a FormatException
. The catch
block in lines 111–115 handles such exceptions by notifying the user (via a MessageBox
) of the improper format.1
If the user entered valid data, lines 95–97 write the record to the file by invoking method WriteLine
of the StreamWriter
object that was created at line 53. 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
(like most of the classes we discuss in this chapter) belongs to the System.IO
namespace. Finally, the TextBox
es are cleared so the user can begin typing the next record’s data.
exitButton_Click
When the user clicks Exit, exitButton_Click
(lines 122–135) executes. Line 126 closes the StreamWriter
(if it is not null
), which automatically closes the underlying FileStream
. Then, line 134 terminates the program. Note that method Close
is called in a try
block. Method Close
throws an IOException
if the file or stream cannot be closed properly. In this case, it’s important to notify the user that the information in the file or stream might be corrupted.
Releasing resources explicitly when they’re no longer needed makes them immediately available for reuse by other programs, thus improving resource utilization.
To test the program, we entered information for the accounts shown in Fig. 17.5. The program does not depict how the data records are stored 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 it in any text editor to see its contents.
Account number | First name | Last name | Balance |
---|---|---|---|
100 |
Nancy |
Brown |
-25.54 |
200 |
Stacey |
Dunn |
314.33 |
300 |
Doug |
Barker |
0.00 |
400 |
Dave |
Smith |
258.34 |
500 |
Sam |
Stone |
34.98 |