Section 18.5. Creating a Sequential-Access Text File


18.5. Creating a Sequential-Access Text File

Visual Basic imposes no structure on files. Thus, the concept of a "record" does not exist in Visual Basic 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 FrmBankUI

The following examples demonstrate file processing in a bank-account maintenance application. These programs have similar user interfaces, so we used the Visual Studio Form designer to create reusable base class FrmBankUI (Fig. 18.7), which encapsulates the common GUI components (see the screen capture in Fig. 18.7). Class FrmBankUI contains four Labels and four TextBoxes. Method ClearTextBoxes (lines 1727) clears the TextBoxes' contents. Method SetTextBoxValues (lines 3049) sets the text in the TextBoxes. Method GetTextBoxValues (lines 5266) gets the values from the TextBoxes.

Figure 18.7. Base class for GUIs in our file-processing applications.

  1  ' Fig. 18.7: FrmBankUI.vb  2  ' A reusable Windows Form for the examples in this chapter.  3  4  Public Class FrmBankUI  5     ' number of TextBoxes on Form  6     Protected TextBoxCount As Integer = 4  7  8     ' enumeration constants specify TextBox indices  9     Public Enum TextBoxIndices 10        ACCOUNT 11        FIRST 12        LAST 13        BALANCE 14     End Enum ' TextBoxIndices 15 16     ' clear all TextBoxes 17     Public Sub ClearTextBoxes() 18        ' iterate through every Control on form 19        For i As Integer = 0 To Controls.Count - 1 20           Dim myControl As Control = Controls(i) ' get control 21           ' determine whether Control is TextBox 22           If TypeOf myControl Is TextBox Then 23              ' clear Text property (set to empty string) 24              myControl.Text = "" 25           End If 26        Next i 27     End Sub ' ClearTextBoxes 28 29     ' set text box values to string array values 30     Public Sub SetTextBoxValues(ByVal values() As String) 31        ' determine whether string array has correct length 32        If values.Length <> TextBoxCount Then 33           ' throw exception if not correct length 34           Throw New ArgumentException( _ 35              "There must be " & (TextBoxCount + 1) & _ 36              " strings in the array") 37           ' set array values if array has correct length 38        Else 39           ' set array values to text box values 40           txtAccount.Text = _ 41              values(Convert.ToInt32(TextBoxIndices.ACCOUNT)) 42           txtFirstName.Text = _ 43              values(Convert.ToInt32(TextBoxIndices.FIRST)) 44           txtLastName.Text = _ 45              values(Convert.ToInt32(TextBoxIndices.LAST)) 46           txtBalance.Text = _ 47              values(Convert.ToInt32(TextBoxIndices.BALANCE)) 48        End If 49     End Sub ' SetTextBoxValues 50 51     ' return text box values as string array 52     Public Function GetTextBoxValues() As String() 53        Dim values(TextBoxCount) As String 54 55        ' copy text box fields to string array 56        values(Convert.ToInt32(TextBoxIndices.ACCOUNT)) = _ 57           txtAccount.Text 58        values(Convert.ToInt32(TextBoxIndices.FIRST)) = _ 59           txtFirstName.Text 60        values(Convert.ToInt32(TextBoxIndices.LAST)) = _ 61           txtLastName.Text 62        values(Convert.ToInt32(TextBoxIndices.BALANCE)) = _ 63           txtBalance.Text 64 65        Return values 66     End Function ' GetTextBoxValues 67  End Class ' FrmBankUI 

To reuse class FrmBankUI, you must compile the GUI into a DLL (we called it BankLibrary) as described in Section 14.13. We provide the BankLibrary with the examples for this chapter. When you copy these examples to your system, you might need to delete the reference to BankLibrary and add it again, since the library most likely will reside in a different location on your system.

Class Record

Figure 18.8 contains class Record, which Fig. 18.9, Fig. 18.11 and Fig. 18.12 use to maintain the data 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 FrmBankUI.

Figure 18.8. Record for sequential-access file-processing applications.

  1   ' Fig. 18.8: Record.vb  2   ' Class that represents a data record.  3   Imports System.Text  4  5   Public Class Record  6      Private accountValue As Integer  7      Private firstNameValue As String  8      Private lastNameValue As String  9      Private balanceValue As Decimal 10 11      ' parameterless constructor sets members to default values 12      Public Sub New() 13         MyClass. New(0, "", "", 0D ) 14      End Sub ' New 15 16      ' overloaded constructor sets members to parameter values 17      Public Sub New(ByVal account As Integer, _ 18         ByVal firstName As String, ByVal lastName As String, _ 19         ByVal balance As Decimal) 20 21         accountValue = account 22         firstNameValue = firstName 23         lastNameValue = lastName 24         balanceValue = balance 25      End Sub ' New 26 27      ' property that gets and sets Account 28      Public Property Account() As Integer 29         Get 30            Return accountValue 31         End Get 32         Set(ByVal value As Integer ) 33             accountValue = value 34         End Set 35      End Property ' Account 36 37      ' property that gets and sets FirstName 38      Public Property FirstName() As String 39         Get 40            Return firstNameValue 41         End Get 42         Set(ByVal value As String) 43           firstNameValue = value 44         End Set 45      End Property ' FirstName 46 47      ' property that gets and sets LastName 48      Public Property LastName() As String 49         Get 50            Return lastNameValue 51         End Get 52         Set(ByVal value As String) 53           lastNameValue = value 54         End Set 55      End Property ' LastName 56 57      ' property that gets and sets Balance 58      Public Property Balance() As Decimal 59         Get 60            Return balanceValue 61         End Get 62         Set(ByVal value As Decimal ) 63            balanceValue = value 64         End Set 65      End Property ' Balance 66   End Class ' Record 

Figure 18.9. Creating and writing to a sequential-access file.

  1   ' Fig. 18.9: FrmCreateFile.vb  2   ' Creating a sequential-access file.  3   Imports System.IO  4   Imports BankLibrary ' imports classes from Figs. 18.7 and 18.8  5  6   Public Class FrmCreateFile  7      Private fileWriter As StreamWriter ' writes data to text file  8      Private output As FileStream ' maintains connection to file  9 10      ' event handler for Save Button 11      Private Sub btnSave_Click(ByVal sender As System.Object, _ 12         ByVal e As System.EventArgs) Handles btnSave.Click 13         ' create dialog box enabling user to save file 14         Dim fileChooser As New SaveFileDialog() 15         Dim result As DialogResult = fileChooser.ShowDialog() 16         Dim fileName As String ' name of file to save data 17 18         fileChooser.CheckFileExists = False ' allow user to create file 19 20         ' exit event handler if user clicked "Cancel" 21         If result = Windows.Forms.DialogResult.Cancel Then 22            Return 23         End If 24 25         fileName = fileChooser.FileName ' get specified file name 26 27         ' show error if user specified invalid file 28         If fileName = "" Or fileName Is Nothing Then 29            MessageBox.Show("Invalid File Name", "Error" , _ 30               MessageBoxButtons.OK, MessageBoxIcon.Error) 31         Else 32            ' save file via FileStream if user specified valid file 33            Try 34               ' open file with write access 35               output = New FileStream( _ 36                  fileName, FileMode.OpenOrCreate, FileAccess.Write) 37 38               ' sets file to where data is written 39               fileWriter = New StreamWriter(output) 40 41               ' disable Save button and enable Enter button 42               btnSave.Enabled = False 43               btnEnter.Enabled = True 44               ' handle exception if there is a problem opening the file 45            Catch ex As IOException 46               ' notify user if file does not exist 47               MessageBox.Show("Error opening file", "Error", _ 48                  MessageBoxButtons.OK, MessageBoxIcon.Error) 49            End Try 50         End If 51      End Sub ' btnSave_Click 52 53      ' event handler for Enter Button 54      Private Sub btnEnter_Click(ByVal sender As System.Object, _ 55         ByVal e As System.EventArgs) Handles btnEnter.Click 56         ' store TextBox values string array 57         Dim values As String() = GetTextBoxValues() 58 59         ' Record containing TextBox values to serialize 60         Dim record As New Record() 61 62         ' determine whether TextBox account field is empty 63         If values(TextBoxIndices.ACCOUNT) <> "" Then 64            ' store TextBox values in Record and serialize Record 65            Try 66               ' get account number value from TextBox 67               Dim accountNumber As Integer = _ 68                  Int32.Parse(values(TextBoxIndices.ACCOUNT)) 69 70               ' determine whether accountNumber is valid 71               If accountNumber > 0 Then 72                  ' store TextBox fields in Record 73                  record.Account = accountNumber 74                  record.FirstName = values(TextBoxIndices.FIRST) 75                  record.LastName = values(TextBoxIndices.LAST) 76                  record.Balance = _ 77                     Decimal.Parse(values(TextBoxIndices.BALANCE)) 78 79                  ' write Record to file, fields separated by commas 80                  fileWriter.WriteLine( _ 81                     record.Account & "," & record.FirstName & "," & _ 82                     record.LastName & "," & record.Balance) 83               Else 84                  ' notify user if invalid account number 85                  MessageBox.Show("Invalid Account Number", "Error" , _ 86                     MessageBoxButtons.OK, MessageBoxIcon.Error) 87               End If 88               ' notify user if error occurs in serialization 89            Catch ex As IOException 90               MessageBox.Show("Error Writing to File", "Error" , _ 91                MessageBoxButtons.OK, MessageBoxIcon.Error) 92             ' notify user if error occurs regarding parameter format 93          Catch ex As FormatException 94             MessageBox.Show("Invalid Format" , "Error" , _ 95                MessageBoxButtons.OK, MessageBoxIcon.Error) 96          End Try 97       End If 98 99       ClearTextBoxes() ' clear TextBox values 100   End Sub ' btnEnter_Click 101 102   ' event handler for Exit Button 103   Private Sub btnExit_Click(ByVal sender As System.Object, _ 104      ByVal e As System.EventArgs) Handles btnExit.Click 105        ' determine whether file exists 106        If output IsNot Nothing Then 107           Try 108              fileWriter.Close() ' close StreamWriter 109              output.Close() ' close file 110              ' notify user of error closing file 111           Catch ex As IOException 112              MessageBox.Show("Cannot close file", "Error", _ 113                 MessageBoxButtons.OK, MessageBoxIcon.Error) 114           End Try 115        End If 116 117        Application.Exit() 118     End Sub ' btnExit_Click 119  End Class ' FrmCreateFile 

(a)

(b)

(c)

(d)

(e)

(f)

(g)

(h)

Class Record contains Private instance variables accountValue, firstNameValue, lastNameValue and balanceValue (lines 69), which collectively represent all the information for a record. The parameterless constructor (lines 1214) sets these members by calling the four-argument constructor with 0 for the account number, empty strings ("") for the first and last names and 0D for the balance. The four-argument constructor (lines 1725) sets these members to the specified parameter values. Class Record also provides properties Account (lines 2835), FirstName (lines 3845), LastName (lines 4855) and Balance (lines 5865) for accessing each record's account number, first name, last name and balance, respectively.

Using a Character Stream to Create an Output File

Class FrmCreateFile (Fig. 18.9) uses instances of class Record to create a sequential-access file that might be used in an accounts-receivable systema 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 that the user could enter the records in any order.

Class FrmCreateFile either creates or opens a file (depending on whether one exists), then allows the user to write records to that file. The Imports statement in line 4 enables us to use the classes of the BankLibrary namespace; this namespace contains class FrmBankUI, from which class FrmCreateFile inherits (specified in the file FrmCreateFile.Designer.vb). Class FrmCreateFile's GUI enhances that of class FrmBankUI with buttons Save As, Enter and Exit.

When the user clicks the Save As button, the program invokes the event handler btnSave_Click (lines 1151). Line 14 instantiates a SaveFileDialog object (namespace System.Windows.Forms). Objects of this class are used for selecting files (see the second screen in Fig. 18.9). Line 15 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 15). Line 21 tests whether the user clicked Cancel by comparing this value to Windows.Forms.DialogResult.Cancel. If the values are equal, method btnSave_Click returns (line 22). Otherwise, line 25 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 3536 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 36) indicates that the FileStream object should open the file if the file exists and 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 (from the FileAccess enumeration) indicates that the program can only perform 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. The StreamWriter object (line 39) 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. Line 45 catches an IOException if there is a problem opening the file or creating the StreamWriter. If so, the program displays an error message (lines 4748). If no exception occurs, the file is open for writing.

Common Programming Error 18.1

Failure to open a file before attempting to reference it in a program is a logic error.


After typing information in each TextBox, the user clicks the Enter button, which calls event handler btnEnter_Click (lines 54100) 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 7377 store the TextBox values in an object of type Record (created in line 60). 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 9395 handles such exceptions by notifying the user (via a MessageBox) of the improper format.

If the user entered valid data, lines 8082 write the record to the file by invoking method WriteLine of the StreamWriter object that was created at line 39. Method WriteLine writes a sequence of characters to a file. We separate each field with a comma in this example, and we place each record on its own line in the file.

When the user clicks the Exit button, event handler btnExit_Click (lines 103118) exits the application. Line 108 closes the StreamWriter, line 109 closes the FileStream, then line 117 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.

Performance Tip 18.1

Close each file explicitly when the program no longer needs to reference the file. This can reduce resource usage in programs that continue executing long after they finish using a specific file. The practice of explicitly closing files also improves program clarity.


Performance Tip 18.2

Releasing resources explicitly when they are no longer needed makes them immediately available for reuse by other programs, thus improving resource utilization.


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 open it in any text editor to see its contents.

Figure 18.10. Sample data for the program in Fig. 18.9

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




Visual BasicR 2005 for Programmers. DeitelR Developer Series
Visual Basic 2005 for Programmers (2nd Edition)
ISBN: 013225140X
EAN: 2147483647
Year: 2004
Pages: 435

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net