VB7 makes some significant changes in the ways you handle arrays and files and completely changes error handling. All of these changes make your programming a lot easier than it was before.
In VB7, all arrays are zero based. This is actually the same as in previous versions of Basic, but it was seldom emphasized. In VB6, if you wrote the following
Dim x(10) As Single
then you assumed that the x array had elements from 1 to 10, but it actually always included a zero element as well. In other words, the x array actually had 11 elements. This remains true in VB7.
However, we can also now move through arrays to be in line with the style used in C, C++, C#, and Java.
Dim Max as Integer Max = 10 Dim x(Max) For j = 0 to Max-1 x(j) = j Next j
However, you can still use
For j = 1 to Max
as you always could.
All array variables have a length property so you can find out how large the array is.
Dim z(20) As Single Dim j As Integer For j = 0 To z.Length – 1 z(j) = j Next j
But beware! The construction
For j = 0 To z.Length – 1
actually moves through 21 elements. If you declare
Dim z(20) As Single
it contains elements from 0 to 20, or 21 in all. So the value of
z.length
is 21, and moving from 0 to z.length –1 is moving through 21 elements. And, if you were to write
For j = 0 To z.Length
You would pass the upper bound of the array. It is safer to write
For j = 0 to Ubound(z) – 1
Arrays in VB7 are dynamic, and you can reallocate space at any time. To create a reference to an array and allocate it later within the class, use the New syntax.
'Declare at the class level Dim x() As Single 'allocate within any method x = New Single(20) { }
Note the unusual use of curly braces following the type and size. This means that you are creating a new array object. This syntax applies because you can also specify the contents of the array in the same declaration:
Dim a() As Single a = New Single() { 1, 3, 4, 5}
You can also use the ReDim statement with or without Preserve to change the size of a declared array. However, you should note that ReDim no longer allows an “As” clause, since the array type cannot be changed during ReDim.
ReDim x(40) ReDim Preserve x(50)
The System.Collections namespace contains a number of useful variable-length array objects you can use to add and obtain items in several ways.
Since arrays are zero-based, VB7 introduces the ArrayList object to replace the Collection object, which was always 1-based. The ArrayList is essentially a variable-length array that you can add items to as needed. The basic ArrayList methods are about the same as for Collections, although there are quite a few more methods you can also use.
Dim i, j As Integer 'create ArrayList Dim arl As New ArrayList() 'constructor 'add to it For j = 0 To 9 Arl.Add(j) Next j
Like the Collection object, the ArrayList has a Count property and an Item property that allows you to obtain elements from it by index. And like the Collection, this property can be omitted, treating the ArrayList just as if it were an array.
'print out contents For i = 0 To arl.Count - 1 Console.writeLine(arl.Item(i)) Console.writeLine(arl(i)) Next i
You can also use the methods of the ArrayList shown in Table 8-1.
A Hashtable is a variable-length array where every entry can be referred to by a key value. Typically, keys are strings of some sort, but that can be any sort of object. Keys must be unique for each element, although the elements themselves need not be unique. Hashtables are used to allow rapid access to one of a large and unsorted set of entries and can also be used by reversing the key and the entry values to create a list where each entry is guaranteed to be unique. The most important Hashtable methods are Add and the Item fetch.
Table 8-1. ArrayList Methods
Clear
| Clears the contents of the ArrayList |
Contains(object)
| Returns true if the ArrayList contains that value |
CopyTo(array)
| Copies entire ArrayList into a one-dimensional array |
IndexOf(object)
| Returns the first index of the value |
Insert(index, object)
| Inserts the element at the specified index |
Remove(object)
| Removes element from list |
RemoveAt(index)
| Removes element from specified position |
Sort
| Sort ArrayList |
Dim hash As New Hashtable() Dim fredObject As New Object() Dim obj As Object hash.Add("Fred", fredObject) obj = hash.Item("Fred")
Hashtables also have a count property, and you can obtain an enumeration of the keys or of the values.
The SortedList class is most like the VB6 Collection class. It maintains two internal arrays, so you can obtain the elements either by zero-based index or by alphabetic key.
Dim sList As New SortedList() slist.Add("Fred", fredObject) slist.Add("Sam", obj) Dim newObj As Object newObj = slist.GetByIndex(0) 'by index newObj = slist.Item("Sam") 'by key
You will also find the Stack and Queue objects in this namespace. They behave much as you'd expect, and you can find their methods in the system help documentation.
Error handling in VB7 is accomplished using exceptions instead of the awkward On Error Goto syntax, which is no longer supported. The thrust of exception handling is that you enclose the statements that could cause errors in a Try block and then catch any errors using a Catch statement.
Try 'Statements Catch e as Exception 'do these if an error occurs Finally 'do these anyway End Try
Typically, you use this approach to test for errors around file handling statements, although you can also catch array index out-of-range statements and a large number of other error conditions. The way this works is that the statements in the Try block are executed, and if there is no error, control passes to the Finally statements, if any, and then on out of the block. If errors occur, control passes to the Catch statement, where you can handle the errors, and then control passes on to the Finally statements and then on out of the block.
The following example shows testing for any exception. Since we are moving one element beyond the end of the ArrayList, an error will occur.
Try For i = 0 To ar.Count 'NOTE: one too many Console.write(ar.Item(i)) Next i Catch e As Exception Console.writeLine(e.Message) Console.writeLine(e.stackTrace) End Try Console.writeline("end of loop")
This code prints out the error message and the calling locations in the program and then goes on.
0123456789Index is out of range. Must be non-negative and less than size. Parameter name: index at System.Collections.ArrayList.get_Item(Int32) at ArrayTest.Main() end of loop
By contrast, if we do not catch the exception, we will get an error message from the runtime system, and the program will exit instead of going on.
Exception occurred: System.ArgumentOutOfRangeException: Index is out of range. Must be non-negative and less than size. Parameter name: index at System.Collections.ArrayList.get_Item(Int32) at ArrayTest.Main() at _vbProject._main(System.String[])
Some of the more common exceptions are shown in Table 8-2.
Table 8-2. VB7 Exceptions
AccessException
| Error in accessing a method or field of a class |
ArgumentException
| Argument to a method is not valid |
ArgumentNullException
| Argument is null |
ArithmeticException
| Overflow or underflow |
DivideByZeroException
| Division by zero |
IndexOutOfRangeException
| Array index out of range |
FileNotFoundException
| File not found |
EndOfStreamException
| Access beyond end of input stream (such as files) |
DirectoryNotFoundException
| Directory not found |
NullReferenceException
| The object variable has not been initialized to a real value |
You can also catch a series of exceptions and handle them differently in the same Try block.
Try For i = 0 To ar.Count Dim k As Integer = CType(ar(i), Integer) Console.writeLine(i.toString & " " & k / i) Next i Catch e As DivideByZeroException Console.writeLine(e.Message) Console.writeLine(e.stackTrace) Catch e As IndexOutOfRangeException Console.writeLine(e.Message) Console.writeLine(e.stackTrace) Catch e As Exception Console.writeLine("general exception" + e.Message) Console.writeLine(e.stackTrace) End Try
This gives you the opportunity to recover from various errors in different ways.
You don't have to deal with exceptions exactly where they occur; you can pass them back to the calling program using the Throw statement. This causes the exception to be thrown in the calling program.
Try 'some code Catch e as Exception Throw e 'pass on to calling routine End Try
You can use some of the file handling functions you are used to in VB6; however, the syntax is rather different because of the requirement that all arguments be enclosed in parentheses. Thus, you will have to make major changes throughout your file handling code.
Input #f, s 'read a string from a file in VB6
becomes
Input(f, s) 'vb6 compatible string read from file
Further, VB7 has no Line Input statement at all. Therefore, it is usually easier to read and write file data using the new File and Stream methods provided in VB7.
The File class provides some useful methods for testing for a file's existence as well as renaming and deleting a file. The File object contains only Shared methods. Thus, you call the File class methods without creating an instance. These are all shared methods in VB parlance. Other languages refer to them as static methods, since they work using the class rather than an object. We show some of the most common File methods in Table 8-3. For a complete list, consult the documentation and help files.
Table 8-3. File Methods
Static Method | Meaning |
---|---|
File.Exists(filename)
| True if file exists |
File.Delete(filename)
| Delete the file |
File.AppendText(String)
| Append text |
File.getAttributes(String)
| Return FileAttributes object |
File.Copy(fromFile, toFile)
| Copy a file |
File.Move(fromFile, toFile)
| Move a file, deleting old copy |
File.OpenText(filename)
| Opens text file for reading |
File.OpenWrite(filename)
| Opens any file for reading |
For example, if you want to delete a file using the File class you check for its existence and then delete it as follows:
If File.Exists("foo.txt") Then 'test existence File.Delete("foo.txt") 'delete it End If
You can also use the File object to obtain a StreamReader or FileStream for reading and writing file data.
Dim ts As StreamReader Dim fs As FileStream ts = File.OpenText("foo.txt") 'open a text file for reading fs = File.OpenRead("foo.data") 'open any file for reading
To read a text file, use the File object to obtain a StreamReader object. Then use the text stream's read methods.
Dim ts As StreamReader ts = File.OpenText("foo.txt") 'open a text file Dim s As String s = ts.ReadLine()
To create and write a text file, use the CreateText method to get a StreamWriter object.
Dim sw As StreamWriter sw = File.CreateText("foo.txt") sw.WriteLine("Hello there")
If you want to append to an existing file, you can create a StreamWriter object directly with the Boolean argument for append set to true.
'appending sw = New StreamWriter("foo.txt", True)
A large number of the most common exceptions occur in handling file input and output. You can get exceptions for illegal filenames, files that do not exist, directories that do not exist, illegal filename arguments, and file protection errors. Thus, the best way to handle file input and output is to enclose file manipulation code in Try blocks to assure yourself that all possible error conditions are caught and thus prevent embarrassing fatal errors. All of the methods of the various file classes show in their documentation which methods they throw. You can be sure that you will catch all of them if you catch only the general Exception object, but if you must take different actions for different exceptions, you can test for them separately.
For example, you might open text files in the following manner.
Try ts = File.OpenText("foo.txt") Catch e As FileNotFoundException 'print out any error Console.WriteLine(e.Message) errFlag = True End Try
There are two useful ways to make sure that you do not pass the end of a text file: looking for a null exception and looking for the end of a data stream. When you read beyond the end of a file, no error occurs and no end of file exception is thrown. However, if you read a string after the end of a file, it will return as a Null value. VB7 does not provide an IsNull method, but you can easily force a Null Reference exception by trying to obtain the length of a string. If you try to execute a length method on a null string, the system will throw a null reference exception, and you can use this to detect the end of a file.
Public Function readLine() As String 'Read one line from the file Dim s As String Try s = ts.readLine 'read line from file lineLength = s.length 'use to catch null exception Catch e As Exception end_file = True 'set EOF flag if null s = "" 'and return zero length string Finally readLine = s End Try End Function
The other way for making sure you don't read past the end of a file is to peek ahead, using the Stream's Peek method. This returns the ASCII code for the next character or a –1 if no characters remain.
'example of alternate approach to detecting end of file Public Function readLineE() As String 'Read one line from the file Dim s As String If ts.peek >= 0 Then 'look ahead s = ts.readLine 'read if more chars Return s Else end_file = True 'Set EOF flag if none left Return "" End If End Function
The FileInfo class has all non-shared methods and operates on a particular filename. You can use it to get information about a particular file:
Method | Meaning |
---|---|
Attributes
| Gets FileAttribute object |
DirectoryName
| Gets file's path |
Extension
| Gets the file's extension |
Length
| Length of the file |
Name
| Gets the file's name |
Exists
| True if file exists |
Delete()
| Deletes the file |
OpenText()
| Creates a StreamReader for reading a text file |
AppendText()
| Creates a StreamWriter to append text to file |
OpenWrite()
| Creates a StreamWriter for output |
For a complete list consult the documentation.
Earlier, we wrote a vbFile class for reading and writing text files a line at a time and a token at a time. We can reimplement this vbFile class for VB7 to have exactly the same methods but utilize the VB7 file handling classes. In essence we are reimplementing the vbFile interface for VB7. Since the syntax remains the same, we might declare formally that we are using the same interface, but since the syntax differs somewhat, we will just write a new class using that same interface.
The main difference is that we can include the filename and path in the constructor. In this example, we use the static File class to obtain the stream reader and writer objects. You can also use an instance of the FileInfo class in a similar fashion. That example is on the CDROM.
Public Sub New(ByVal filename As String) 'Create new file instance File_name = filename 'save file name tokLine = "" 'initialize tokenizer sep = "," 'and separator End Sub
We can open a file for reading using either of two methods: one including the filename and one that uses a filename in the argument.
Public Overloads Function OpenForRead() As Boolean Return OpenForRead(file_name) End Function '---------------- Public Overloads Function OpenForRead(_ ByVal Filename As String) As Boolean 'opens specified file file_name = Filename 'save file name errFlag = False 'clear errors end_File = False 'and end of file Try ts = fl.Opentext() 'open the file Catch e As Exception errDesc = e.Message 'save error message errFlag = True 'and flag End Try Return Not errFlag 'false if error End Function
You can then read data from the text file as we just illustrated.
Likewise, the following methods allow you to open a file for writing and write lines of text to it.
Public Overloads Function OpenForWrite( _ ByVal fname As String) As Boolean errFlag = False Try File_name = fname sw = File.CreateText(File_name) 'get StreamWriter Catch e As Exception errDesc = e.Message errFlag = True End Try OpenForWrite = Not errFlag End Function '------------- Public Overloads Function OpenForWrite() As Boolean OpenForWrite = OpenForWrite(file_name) End Function '------------- Public Sub writeText(ByVal s As String) sw.writeLine(s) 'write text to stream End Sub
Since we have implemented the same methods in our new vbFile class as for the VB6 class, we can substitute the new one and use it with VB7 programs without changing the surrounding programs at all.
FilesArraysExceptionsArray
| Showcase use of arrays and ArrayList |
FilesArraysExceptionsExceptions
| Illustrates how to use exceptions |
FilesArraysExceptionsFileObject
| Shows VB7 implementation of the vbFile class using the File object. |
FilesArraysExceptionsFileStream
| Shows VB7 implementation of the vbFile class using the FileInfo object. |