18.7. Case Study: A Credit-Inquiry Program To retrieve data sequentially from a file, programs normally start from the beginning of the file, reading consecutively until the desired data is found. It sometimes is necessary to process a file sequentially several times (from the beginning of the file) during the execution of a program. A FileStream object can reposition its file-position pointer (which contains the byte number of the next byte to be read from or written to the file) to any position in the file. When a FileStream object is opened, its file-position pointer is set to byte position 0 (i.e., the beginning of the file) We now present a program that builds on the concepts employed in Fig. 18.11. Class FrmCreditInquiry (Fig. 18.12) is a credit-inquiry program that enables a credit manager to search for and display account information for customers with credit balances (i.e., customers to whom the company owes money), zero balances (i.e., customers who do not owe the company money) and debit balances (i.e., customers who owe the company money for previously received goods and services). We use a RichTextBox in the program to display the account information. RichTextBoxes provide more functionality than regular TextBoxesfor example, RichTextBoxes offer method Find for searching individual strings and method LoadFile for displaying file contents. Classes RichTextBox and TextBox both inherit from MustInherit class System.Windows.Forms.TextBoxBase. We chose a RichTextBox in this example because it displays multiple lines of text by default, whereas a regular TextBox displays only one. Alternatively, we could have specified that a TextBox object display multiple lines of text by setting its Multiline property to true. Figure 18.12. Credit-inquiry program. 1 ' Fig. 18.12: FrmCreditInquiry.vb 2 ' Read a file sequentially and display contents based on 3 ' account type specified by user (credit, debit or zero balances). 4 Imports System.IO 5 Imports BankLibrary 6 7 Public Class FrmCreditInquiry 8 Private input As FileStream ' maintains the connection to the file 9 Private fileReader As StreamReader ' reads data from text file 10 11 ' name of file that stores credit, debit and zero balances 12 Private fileName As String 13 14 ' invoked when user clicks Open File button 15 Private Sub btnOpen_Click(ByVal sender As System.Object, _ 16 ByVal e As System.EventArgs) Handles btnOpen.Click 17 ' create dialog box enabling user to open file 18 Dim fileChooser As New OpenFileDialog() 19 Dim result As DialogResult = fileChooser.ShowDialog() 20 21 ' exit event handler if user clicked Cancel 22 If result = Windows.Forms.DialogResult.Cancel Then 23 Return 24 End If 25 26 fileName = fileChooser.FileName ' get name from user 27 28 ' show error if user specified invalid file 29 If fileName = "" Or fileName Is Nothing Then 30 MessageBox.Show( "Invalid File Name", "Error", _ 31 MessageBoxButtons.OK, MessageBoxIcon.Error) 32 Else 33 ' create FileStream to obtain read access to file 34 input = New FileStream(fileName, FileMode.Open, FileAccess.Read ) 35 36 ' set file from where data is read 37 fileReader = New StreamReader(input) 38 39 ' enable all GUI buttons, except for Open File button 40 btnOpen.Enabled = False 41 btnCredit.Enabled = True 42 btnDebit.Enabled = True 43 btnZero.Enabled = True 44 End If 45 End Sub ' btnOpen_Click 46 47 ' invoked when user clicks credit balances, 48 ' debit balances or zero balances button 49 Private Sub getBalances_Click( _ 50 ByVal sender As System.Object, ByVal e As System.EventArgs) _ 51 Handles btnCredit.Click, btnZero.Click, btnDebit.Click 52 ' convert sender explicitly to object of type button 53 Dim senderButton As Button = CType(sender, Button) 54 55 ' get text from clicked Button, which stores account type 56 Dim accountType As String = senderButton.Text 57 58 ' read and display file information 59 Try 60 ' go back to the beginning of the file 61 input.Seek(0, SeekOrigin.Begin) 62 63 txtDisplay.Text = "The accounts are:" & vbCrLf 64 65 ' traverse file until end of file 66 While True 67 ' will store individual pieces of data 68 Dim inputFields() As String 69 70 Dim record As Record ' store each Record as file is read 71 Dim balance As Decimal ' store each Record's balance 72 73 ' get next Record available in file 74 Dim inputRecord As String = fileReader.ReadLine() 75 76 ' when at the end of file, exit method 77 If inputRecord Is Nothing Then 78 Return 79 End If 80 81 inputFields = inputRecord.Split( ","c ) ' parse input 82 83 ' create Record from input 84 record = New Record(Convert.ToInt32( _ 85 inputFields(0)), inputFields(1), inputFields(2), _ 86 Convert.ToDecimal(inputFields(3))) 87 88 ' store record's last field in balance 89 balance = record.Balance 90 91 ' determine whether to display balance 92 If ShouldDisplay(balance, accountType) Then 93 ' display record 94 Dim output As String = _ 95 record.Account & vbTab & _ 96 record.FirstName & vbTab & _ 97 record.LastName & vbTab 98 99 ' display balance with correct monetary format 100 output &= String.Format("{0:F}", balance) & vbCrLf 101 102 txtDisplay.Text &= output ' copy output to screen 103 End If 104 End While 105 ' handle exception when file cannot be read 106 Catch ex As IOException 107 MessageBox.Show( "Cannot Read File", "Error" , _ 108 MessageBoxButtons.OK, MessageBoxIcon.Error ) 109 End Try 110 End Sub ' getBalances_Click 111 112 ' determine whether to display given record 113 Private Function ShouldDisplay(ByVal balance As Decimal, _ 114 ByVal accountType As String) As Boolean 115 116 If balance > 0 Then 117 ' display credit balances 118 If accountType = "Credit Balances" Then 119 Return True 120 End If 121 ElseIf balance < 0 Then 122 ' display debit balances 123 If accountType = "Debit Balances" Then 124 Return True 125 End If 126 Else ' balance = 0 127 ' display zero balances 128 If accountType = "Zero Balances" Then 129 Return True 130 End If 131 End If 132 133 Return False 134 End Function ' ShouldDisplay 135 136 ' invoked when user clicks Done button 137 Private Sub btnDone_Click(ByVal sender As System.Object, _ 138 ByVal e As System.EventArgs) Handles btnDone.Click 139 ' determine whether file exists 140 If input IsNot Nothing Then 141 ' close file and StreamReader 142 Try 143 input.Close() 144 fileReader.Close() 145 ' handle exception if FileStream does not exist 146 Catch ex As IOException 147 ' notify user of error closing file 148 MessageBox.Show( "Cannot close file", "Error", _ 149 MessageBoxButtons.OK, MessageBoxIcon.Error) 150 End Try 151 End If 152 153 Application.Exit() 154 End Sub ' btnDone_Click 155 End Class ' FrmCreditInquiry
(a)
(b)
(c)
(d)
(e) | The program displays buttons that enable a credit manager to obtain credit information. The Open File button opens a file for gathering data. The Credit Balances button displays a list of accounts that have credit balances, the Debit Balances button displays a list of accounts that have debit balances and the Zero Balances button displays a list of accounts that have zero balances. The Done button exits the application. When the user clicks the Open File button, the program calls the event handler btnOpen_Click (lines 1545). Line 18 creates an OpenFileDialog, and line 19 calls its ShowDialog method to display the Open dialog, in which the user selects the file to open. Line 34 creates a FileStream object with read-only file access and assigns it to reference input. Line 37 creates a StreamReader object that we use to read text from the FileStream. When the user clicks Credit Balances, Debit Balances or Zero Balances, the program invokes method getBalances_Click (lines 49110). To create a single method that handles the events for multiple Buttons, select the Click event in the Properties window for one of the Buttons, type the name you wish to use for the event handler and press Enter. Then modify the Handles clause for the method so that it is followed by a comma separated list of the events the method handles, as shown in line 51. Line 53 uses Visual Basic's CType function to convert the sender parameter's type, which is an Object reference, to type Button. The sender parameter represents the control that generated the event. This conversion allows the event handler to use the properties and methods of the Button the user pressed. A conversion performed with the CType function is also known as a cast operation. Line 56 obtains the Button object's text, which the program uses to determine which type of accounts to display. Line 61 uses FileStream method Seek to reset the file-position pointer back to the beginning of the file. FileStream method Seek allows you to reset the file-position pointer by specifying the number of bytes it should be offset from the file's beginning, end or current position. The part of the file you want to be offset from is chosen using constants from the SeekOrigin enumeration. In this case, our stream is offset by 0 bytes from the file's beginning (SeekOrigin.Begin). Lines 66104 loop using Private method ShouldDisplay (lines 113134) to determine whether to display each record in the file. The loop obtains each record by repeatedly calling StreamReader method ReadLine (line 74) and splitting the text into tokens that are used to initialize object record (lines 8186). Line 77 determines whether the end of the file has been reached. If so, the program returns from method getBalances_Click (line 78). |