8.1. Sequential FilesThroughout this text, we have processed data from files created with Windows Notepad and saved on a disk. Such files are stored on disk as a sequence of characters. (Two special characters, called "carriage return" and "line feed", are inserted at the end of each line to indicate where new lines should be started.) These files are called sequential files or text files. In this section, we create sequential files with Visual Basic programs and develop techniques for using sequential files. Creating a Sequential FileThere are many ways to organize data in a sequential file. As done throughout the book so far, we will continue to have each line contain just one piece of data. The following steps create a new sequential file and write data to it:
This statement breaks the communications link with the file and frees up space in memory. Once a sequential file has been created, you can look at it with Notepad. Alternatively, the entire file can be displayed in a list box. Example 1.
Caution: If an existing file is opened for output, Visual Basic will erase the existing file and create a new empty file. The WriteLine method allows us to create files just like the Notepad files that appear throughout this text. We already know how to read such files with the ReadLine method. The remaining major task is adding data to the end of a sequential file. Adding Items to a Sequential FileData can be added to the end of an existing sequential file with the following steps:
The IO.File.AppendText option is used to add data to an existing file. However, it also can be used to create a new file. If the file does not exist, then the IO.File.AppendText option creates the file. The three options, CreateText, OpenText, and AppendText, are referred to as modes. A file should not be open in two modes at the same time. For instance, after a file has been opened for output and data have been written to the file, the file should be closed before being opened for input. For instance, had the statement sw.Close() in Example 1 been omitted, then the program would have crashed when the second button was clicked. An attempt to open a nonexistent file for input terminates the program with a FileNotFoundException message box stating that the file could not be found. There is a method that tells us whether a certain file already exists. If the value of IO.File.Exists(filespec) is True, then the specified file exists. Therefore, prudence dictates that files be opened for input with code such as Dim sr As IO.StreamReader If IO.File.Exists(filespec) Then sr = IO.File.OpenText(filespec) Else message = "Either no file has yet been created or the file " message &= filespec & " is not where expected." MsgBox(message, 0, "File Not Found") End If There is one file-management operation that we have yet to discuss: changing or deleting an item of information from a sequential file. An individual item of a file cannot be changed or deleted directly. A new file must be created by reading each item from the original file and recording it, with the single item changed or deleted, into the new file. The old file is then erased, and the new file renamed with the name of the original file. Regarding these last two tasks, the Visual Basic statement IO.File.Delete(filespec) removes the specified file from the disk, and the statement IO.File.Move (oldfilespec, newfilespec) changes the filespec of a file. (Note: The IO.File.Delete and IO.File.Move methods cannot be used with open files; doing so generates an error message.) Creating a program that has extensive file handling can be simplified by placing the statement Imports System.IO at the top of the Code window, before the Class frmName statement. Then, there is no need to insert the prefix "IO." before the words StreamReader, StreamWriter, and File. Example 2. |
![]() The following program manages a file of names and years of birth:
Imports System.IO 'Appears at top of code window Private Sub btnAdd_Click(...) Handles btnAdd.Click 'Add a person's name and year of birth to file Dim message As String If (txtName.Text <> "") And (mtxtYOB.Text <> "") Then Dim sw As StreamWriter = File.AppendText("YOB.TXT") sw.WriteLine(txtName.Text) sw.WriteLine(mtxtYOB.Text) [Run. After several names have been added, the file might look as shown in Figure 8.1.]
|
There are two main types of problems that a software program might encounter when it executes. The first is a bug, which is caused by incorrect or faulty code. Common examples of bugs are typos, using the wrong formula, and accessing the wrong property value. The second type is an exception, which, as the term suggests, is a situation that happens occasionally, but not all the time. Two situations where exceptions occur are when invalid data are input and when a file cannot be accessed.
The fundamental difference between bugs and exceptions is that bugs are totally caused by the programmer while exceptions are caused by events beyond the programmer's control. For example, if a user enters a word when the program prompts for a number, an exception is generated and the program terminates abruptly. In this situation, the programmer did not employ faulty logic or mistype. If the user had followed the directions, no problem would have occurred. Even though the user is at fault, however, it is still the programmer's responsibility to anticipate exceptions and to include code to work around their occurrence.
The Visual Studio environment contains powerful tools that programmers can use to find and correct bugs. These debugging tools are discussed extensively in Appendix D. This section describes the techniques used to anticipate and deal with exceptions (in programming terms, called "handling exceptions").
An unexpected problem causes Visual Basic first to throw an exception and then to handle it. If the programmer does not explicitly include exception-handling code in the program, then Visual Basic handles an exception with a default handler. This handler terminates execution, displays the exception's message in a window and highlights the line of code where the exception occurred. Consider a program that contains the following code:
Dim taxCredit As Double Private Sub btnCompute_Click(...) Handles btnCompute.Click Dim numDependents As Integer numDependents = CInt(InputBox("How many dependents?")) taxCredit = 1000 * numDependents End Sub
A user with no dependents might just leave the input dialog box blank and press the OK button. If so, Visual Basic terminates the program and displays the window shown in Figure 8.2. (The problem was caused by the fact that the default value in an input dialog box, the empty string, cannot be converted to an integer. Text boxes also have the empty string as their default value.) It also highlights the fourth line of code since the exception was thrown while executing the CInt function. The program also would have crashed had the user typed in an answer like "TWO".
A robust program explicitly handles the previous exception by protecting the code in a Try-Catch-Finally block. This allows the program to continue regardless of whether an exception was thrown. The computer tries to execute the code in the Try block. As soon as an exception occurs, execution jumps to the code in the Catch block. Regardless of whether an exception occurred, the code in the Finally block is then executed. The following code is illustrative:
Dim taxCredit As Double Private Sub btnCompute_Click(...) Handles btnCompute.Click Dim numDependents As Integer, message As String Try numDependents = CInt(InputBox("How many dependents?")) Catch message = "You did not answer the question with an " & _ "integer value. We will assume your answer is zero." MsgBox(message) numDependents = 0 Finally taxCredit = 1000 * numDependents End Try End Sub
This type of exception handling is known as data validation. It catches situations where invalid data cannot be converted to a particular type. An exception is thrown if the user enters data that cannot be converted to an integer using the CInt function. Table 8.1 lists several exceptions and descriptions of why they are thrown.
Exception Name | Description and Example |
---|---|
ArgumentOutOfRangeException | An argument to a method is out of range.
str = "Goodbye".Substring(12,3) |
IndexOutOfRangeException | An array's subscript is out of range.
Dim arr(3) As Integer arr(5) = 2 |
InvalidCastException | A value cannot be converted to another type.
Dim num As Integer = CInt("one") |
NullReferenceException | A method is called on a variable that is set to Nothing.
Dim str As String, len As Integer len = str.Length |
OverflowException | A number too big for the data type is stored.
Dim num As Integer = 2000000000 num = 2 * num |
IO.DirectoryNotFoundException | A file within a missing folder is accessed.
Dim sr As IO.StreamReader = _ IO.File.OpenText("C:\BadDir\FILE.TXT") |
IO.FileNotFoundException | A missing file is accessed.
Dim sr As IO.StreamReader = _ IO.File.OpenText("MISSING.TXT") |
IO.EndOfStreamException | Takes place when an attempt to read beyond the end of the file has been made.
Dim sr As StreamReader = _ IO.File.OpenText("NAMES.TXT") 'Empty file Dim name as String name = sr.ReadLine |
IO.IOException | Any file handling exception, including those mentioned above. For instance, an attempt is made to delete or rename an open file, to change the name of a closed file to an already used name, or when a disk drive specified contains no disk. Note: If a series of IO exceptions is being tested with Catch clauses, this exception should be the last one tested.
IO.File.Move(filespec, AlreadyExistingName) |
This Catch block will be executed whenever any exception occurs. Visual Basic also allows Try-Catch-Finally blocks to have one or more specialized Catch clauses that only handle a specific type of exception. The general form of a specialized Catch clause is
Catch exc As ExceptionName
where the variable exc will be assigned the name of the exception. The code in this block will be executed only when the specified exception occurs.
The general form of a Try-Catch-Finally block is
Try normal code Catch exc1 As FirstException exception-handling code for FirstException Catch exc2 As SecondException exception-handling code for SecondException . .[Page 421] Catch exception-handling code for any remaining exceptions Finally clean-up code End Try
The normal code is the code that you want to monitor for exceptions. If an exception occurs during execution of any of the statements in this section, Visual Basic transfers control to the code in one of the Catch blocks. As with a Select Case block, the Catch clauses are considered one at a time until the proper exception is located. The last Catch clause in the preceding code functions like the Case Else clause. The clean-up code in the Finally block always executes last regardless of whether any exception-handling code has executed. In most situations, this code cleans up any resources such as files that were opened during the normal code. If clean-up is not necessary, then the Finally statement and its corresponding code can be omitted. However, to complete a Try block, a Catch block or a Finally block must appear.
In addition to data validation, a popular use of exception handling is to account for errors when accessing files. Visual Basic has the capability to access files stored on distant servers via the Internet. An exception is thrown if a desired file is missing (IO.FileNotFoundException) or if the file cannot be read because the Internet connection between the computer and the server is broken (IO.IOException).
![]() The following program reads the first line from a file on a diskette. The program expects the file to reside in the root directory of a floppy disk. Note that the clean-up code, sr.Close(), in the Finally block is enclosed in a Try-Catch block of its own. This protects the Close method from any exceptions that might occur. Private Sub btnDisplay_Click(...) Handles btnDisplay.Click Dim sr As IO.StreamReader Dim message As String Try sr = IO.File.OpenText("A:\DataFiles\USPRES.TXT") message = "The first President was " & sr.ReadLine & "." MsgBox(message, 0, "President") Catch exp As IO.DirectoryNotFoundException message = "The requested folder is not on the diskette." MsgBox(message, 0, "Error") Catch exp As IO.FileNotFoundException message = "File not in specified folder of diskette." MsgBox(exp.Message, 0, "Error") Catch exp As IO.IOException message = "Check to see if there is a diskette in drive A:." MsgBox(message, 0, "Error") Finally Try sr.Close() [Remove the diskette from the A: drive, run the program, and then click on the button.] [Insert a diskette containing the file USPRES.TXT (in the folder DataFiles) into the A: drive] |
Sequential files make efficient use of disk space and are easy to create and use. Their disadvantages are as follows:
Often a large portion of the file must be read in order to find one specific item.
An individual item of the file cannot be changed or deleted easily.
Another type of file, known as a database, has neither of the disadvantages of sequential files; however, databases use more disk space, and require greater effort to program. Databases are discussed in Chapter 10.
Consider the sequential file shown at the end of Example 2. This file is said to consist of three records of two fields each. A record holds all the data about a single individual. Each item of data is called a field. The three records are
Barbra | Ringo | Sylvester |
1942 | 1940 | 1946 |
and the two fields are the name field and the year-of-birth field.
Any variable declared within a Try-Catch-Finally block has block-level scope. That is, it will not be available after the block terminates.
1. | Compose a Sub procedure RemoveDups that could be used in Example 2 to delete from YOB.TXT all repeated records except the first instance of a name matching the name in txtName. (Assume that the existence of YOB.TXT is checked prior to the execution of this Sub procedure.) |
2. | Compose a Sub procedure AddNoDuplicate to add a name and year of birth to the end of the file YOB.TXT only if the name to be added is not already present in the file. (Assume that the existence of YOB.TXT is checked prior to the execution of this Sub procedure.) |
In Exercises 1 through 10, determine the output displayed in the text box when the button is clicked.
1. | Private Sub btnDisplay_Click(...) Handles btnDisplay.Click Dim salutation As String Dim sw As IO.StreamWriter = IO.File.CreateText("GREETINGS.TXT") sw.WriteLine("Hello") sw.WriteLine("Aloha") sw.Close() Dim sr As IO.StreamReader = IO.File.OpenText("GREETINGS.TXT") salutation = sr.ReadLine txtOutput.Text = salutation sr.Close() End Sub | |||
2. | Private Sub btnDisplay_Click(...) Handles btnDisplay.Click Dim salutation, welcome As String Dim sw As IO.StreamWriter = IO.File.CreateText("GREETINGS.TXT") sw.WriteLine("Hello") sw.WriteLine("Aloha") sw.Close() Dim sr As StreamReader = IO.File.OpenText("GREETINGS.TXT") salutation = sr.ReadLine welcome = sr.ReadLine txtOutput.Text = welcome sr.Close() End Sub | |||
3. | Private Sub btnDisplay_Click(...) Handles btnDisplay.Click Dim salutation As String Dim sw As IO.StreamWriter = IO.File.CreateText("GREETINGS.TXT") sw.WriteLine("Hello") sw.WriteLine("Aloha") sw.WriteLine("Bon Jour") | |||
4. | Assume that the contents of the file GREETING.TXT are as shown in Figure 8.3.
Private Sub btnDisplay_Click(...) Handles btnDisplay.Click Dim file, welcome As String file = "GREETING.TXT" Dim sw As IO.StreamWriter = IO.File.AppendText(file) sw.WriteLine("Buenos Dias") sw.Close() Dim sr As IO.StreamReader = IO.File.OpenText(file) For salutation As Integer = 1 To 4 welcome = sr.ReadLine txtOutput.Text = welcome Next sr.Close() End Sub | |||
5. | Private Sub btnDisplay_Click(...) Handles btnDisplay.Click Dim num As Integer 'Assume that txtBox is empty Try num = CInt(txtBox.Text) txtOutput.Text = "Your number is " & num Catch txtOutput.Text = "You must enter a number." End Try End Sub | |||
6. | Private Sub btnDisplay_Click(...) Handles btnDisplay.Click Dim nafta() As String = {"Canada", "United States", "Mexico"} Try txtOutput.Text = "The third member of NAFTA is " & nafta(3) Catch exc As IndexOutOfRangeException txtOutput.Text = "Error occurred." End Try End Sub | |||
7. | Private Sub btnDisplay_Click(...) Handles btnDisplay.Click Try Dim usPop As Integer = 300000000 'Approx population of U.S. Dim worldPop As Integer worldPop = 21 * usPop txtOutput.Text = CStr(worldPop) Catch exc As ArgumentOutOfRange txtOutput.Text = "Oops" Catch exc As OverflowException txtOutput.Text = "Error occurred." End Try End Sub | |||
8. | Private Sub btnDisplay_Click(...) Handles btnDisplay.Click Dim flower As String = "Bougainvillaea", lastLetter As String Try lastLetter = flower.Substring(14, 1) txtOutput.Text = lastLetter Catch exc As InvalidCastException txtOutput.Text = "Oops" Catch exc As ArgumentOutOfRangeException txtOutput.Text = "Error occurred." End Try End Sub | |||
9. | Assume that the file AGES.TXT is located in the Debug subfolder of the project folder bin and the first line of the file is "Twenty-one". Private Sub btnDisplay_Click(...) Handles btnDisplay.Click Dim sr As IO.StreamReader Dim age As Integer Try sr = IO.File.OpenText("AGES.TXT") 'FileNotFound if fails age = CInt(sr.ReadLine) 'InvalidCast if fails txtOutput.Text = "Age is " & age Catch exc As IO.FileNotFoundException txtOutput.Text = "File AGES.TXT not found" Catch exc As InvalidCastException txtOutput.Text = "File AGES.TXT contains an invalid age." Finally Try sr.Close() 'This code executes no matter what happens above Catch 'Disregard any exceptions thrown during the Close() method End Try End Try End Sub | |||
10. | Redo Exercise 9 with the assumption that the file AGES.TXT is not located in the Debug subfolder of the project folder bin. | |||
11. | Assume that the contents of the file GREETING.TXT are as shown in Figure 8.3. What is the effect of the following program? Private Sub btnDisplay_Click(...) Handles btnDisplay.Click Dim g As String Dim sr As IO.StreamReader = IO.File.OpenText("GREETING.TXT") Dim sw As IO.StreamWriter = IO.File.CreateText("WELCOME.TXT") Do While (sr.Peek <> -1) g = sr.ReadLine If (g <> "Aloha") Then sw.WriteLine(g) End If Loop sr.Close() sw.Close() End Sub | |||
12. | Assume that the contents of the file YOB.TXT are as shown in Figure 8.1 (on page 418). What is the effect of the following program? Private Sub btnDisplay_Click(...) Handles btnDisplay.Click Dim flag As Boolean, name As String, year As Integer Dim sr As IO.StreamReader = IO.File.OpenText("YOB.TXT") Dim sw As IO.StreamWriter = IO.File.CreateText("YOB2.TXT") flag = False name = "" Do While (name < "Clint") And (sr.Peek <> -1) name = sr.ReadLine year = CInt(sr.ReadLine) If name >= "Clint" Then sw.WriteLine("Clint") sw.WriteLine(1930) flag = True End If sw.WriteLine(name) sw.WriteLine(year) Loop Do While (sr.Peek <> -1) name = sr.ReadLine year = CInt(sr.ReadLine) sw.WriteLine(name) sw.WriteLine(year) Loop If Not flag Then sw.WriteLine("Clint") sw.WriteLine(1930) End If sr.Close() sw.Close() End Sub |
In Exercises 13 through 18, identify any errors. Assume that the contents of the files YOB.TXT and GREETING.TXT are as shown in Figures 8.1 and 8.3.
13. | Private Sub btnDisplay_Click(...) Handles btnDisplay.Click Dim sw As IO.StreamWriter = IO.File.AppendText(YOB.TXT) sw.WriteLine("Michael") sw.WriteLine(1965) sw.Close() End Sub |
14. | Private Sub btnDisplay_Click(...) Handles btnDisplay.Click Dim name As String, yr As Integer Dim sw As IO.StreamWriter = IO.File.CreateText("YOB.TXT") name = sw.Readline yr = CInt(sw.ReadLine) txtOutput.Text = name sw.Close() End Sub |
15. | Private Sub btnDisplay_Click(...) Handles btnDisplay.Click 'Copy the contents of the file GREETING.TXT into the file NEWGREET.TXT Dim name, greeting As String Dim sr As IO.StreamReader = IO.File.OpenText("GREETING.TXT") name = "NEWGREET.TXT" Dim sw As IO.StreamWriter = IO.File.CreateText("name") Do While (sr.Peek <> -1) greeting = sr.ReadLine sw.WriteLine(greeting) Loop sr.Close() sw.Close() End Sub |
16. | Private Sub btnDisplay_Click(...) Handles btnDisplay.Click Dim sw As IO.StreamReader = IO.File.CreateText("GREETING.TXT") "GREETING.TXT".Close() End Sub |
17. | Private Sub btnDisplay_Click(...) Handles btnDisplay.Click Try Dim age As Integer age = CInt(InputBox("Enter your age.")) Catch MsgBox("Invalid age.") End Try MsgBox("You are " & age & " years old") End Sub |
18. | Private Sub btnDisplay_Click(...) Handles btnDisplay.Click Dim sw As IO.StreamWriter Try sw = IO.File.CreateFile("A:\LAKES.TXT") |
Exercises 19 through 24 are related and use the data in Table 8.2. The file created in Exercise 19 should be used in Exercises 20 through 24.
19. | Write a program to create the sequential file COWBOY.TXT containing the information in Table 8.2.
| ||||||||||
20. | Suppose the price of saddles is reduced by 20%. Use the file COWBOY.TXT to create a sequential file, COWBOY3.TXT, containing the new price list. | ||||||||||
21. | Write a program to add the data Winchester rifle, 20.50 to the end of the file COWBOY.TXT. | ||||||||||
22. | Suppose an order is placed for 3 Colt Peacemakers, 2 Holsters, 10 pairs of Levi Strauss Jeans, 1 saddle, and 4 Stetsons. Write a program to perform the following tasks:
| ||||||||||
23. | Write a program to request an additional item and price from the user. Then create a sequential file called COWBOY2.TXT containing all the information in the file COWBOY.TXT with the additional item (and price) inserted in its proper alphabetical sequence. Run the program for both of the following data items: Boots, 20 and Horse, 35. | ||||||||||
24. | Write a program to allow additional items and prices to be input by the user and added to the end of the file COWBOY.TXT. Include a method to terminate the process. | ||||||||||
25. | Suppose that the file YOB.TXT contains many names and years and that the names are in alphabetical order. Write a program that requests a name as input and either gives the person's age in 2006 or reports that the person is not in the file. Note: Because the names are in alphabetical order, usually there is no need to search to the end of the file. | ||||||||||
26. | Suppose the file YOBS.TXT contains many names and years. Write a program that creates two files, called SENIORS.TXT and JUNIORS.TXT, and copies all the data on people born before 1940 into the file SENIORS.TXT and the data on the others into the file JUNIORS.TXT. | ||||||||||
27. | A publisher maintains two sequential files, HARDBACK.TXT and PAPERBACK.TXT. Each record consists of the name of a book and the quantity in stock. Write a program to access these files. (The program should allow for the case when the book is not in the file.) A run of the program might look as follows: | ||||||||||
28. | Visual Basic cannot erase a file that is open. Attempting to do so generates an exception. Write a short program that uses structured exception handling to handle such an exception. |
1. | A record in YOB.TXT is kept if the name in the record does not match the search name, or if the name in the record matches the search name and a flag indicates that the search name has not been found previously. Private Sub RemoveDups() Dim name As String, yob As Integer, foundFlag As Boolean foundFlag = False Dim sr As IO.StreamReader = IO.File.OpenText("YOB.TXT") Dim sw As IO.StreamWriter = IO.File.CreateText("TEMP.TXT") Do While sr.Peek <> -1 name = sr.ReadLine yob = CInt(sr.ReadLine) If name <> txtName.Text Then sw.WriteLine(name) sw.WriteLine(yob) Else If Not foundFlag Then sw.WriteLine(name) sw.WriteLine(yob) End If |
2. | The file YOB.TXT is first opened for input and scanned for the new name. If the name is not found, YOB.TXT is reopened for Append and the name and year of birth are added to the end of the file. Private Sub AddNoDuplicate() Dim name As String, yob As Integer, foundFlag As Boolean Dim sr As IO.StreamReader = IO.File.OpenText("YOB.TXT") foundFlag = False Do While (sr.Peek <> -1) And (Not foundFlag) name = sr.ReadLine yob = CInt(sr.ReadLine) If name = txtName.Text Then foundFlag = True End If Loop sr.Close() If Not foundFlag Then Dim sw As IO.StreamWriter = IO.File.AppendText("YOB.TXT") sw.WriteLine(txtName.Text) sw.WriteLine(mtxtYOB.Text) sw.Close() End If End Sub |