Visual Basic offers an assortment of functions for the manipulation of files and directories. This chapter covers the methods that can be used to open and read from files, write to files, navigate open files, and obtain information about a file. First,
the basics of file input and output (I/O) are covered, followed by more advanced topics including reading files in blocks, binary chops, and file formats.
Examples in this chapter use variables created in the following format:
Preceded with |
Variable Type |
Example |
i |
Integer |
iCounter |
s |
String |
sDirName |
l |
Long |
lByteCount |
t |
Type Structure |
tMyType |
|
|
|
This key should simplify the examples provided. Additionally, each example explicitly declares the variables that it uses.
This section covers the basics of file input and output (I/O) in Visual Basic. This section mirrors functionality that already exists in Visual Basic 3.0. The section is organized into keywords in two major sections: creating and deleting files and
directories, and accessing files. Each statement or function discussed is fully explained and examples are provided where appropriate.
Files and directories can be created and deleted using numerous Visual Basic operations. The following covers each of the functions and statements associated with directory creation and deletion. This is an area where error checking is of the utmost
importance, especially when creating and deleting across network drives.
The MkDir function is used to create a new directory on a drive. The directory to be created is passed as an argument. For example:
MkDir "C:\WINDOWS\MYDIR"
This command creates a new directory given that the path provided exists. When creating a directory, many different errors can be encountered. The following example creates a directory. The function returns a value for Err as a result. If Err does not
equal 0, an error occurred.
Function CreateDirectory(sDirectory As String) 'Set Up Error Handler On Error GoTo CreateDirectory_ErrorHandler 'Create the directory MkDir sDirectory CreateDirectory_ErrorHandler: Select Case Err Case 0 MsgBox "Error " & Error$ Occurred Case 1 MsgBox "Error " & Error$ Occurred Case 2 MsgBox "Error " & Error$ Occurred End Select 'Return the error as the result of the function CreateDirectory = Err End Function Usage: Dim sDirectory As String Dim iRet as Integer sDirectory = "C:\PROJECTS\PROJECT1" iRet = Createdirectory(sDirectory) If iRet = 0 Then 'OK to continue...
This statement is used to move a file from one directory to another on the same drive. This statement takes the following parameters:
sFromLoc—This is the name of the source file including the fully qualified path, for example: C:\OLDDIR\FROMFILE.TXT.
sToLoc—This is the name of the target file including the fully qualified path, for example, C:\NEWDIR\TOFILE.TXT.
There are several items to note when using this statement.
Attempting any of these actions results in an error (Err <> 0).
The following function uses the Name statement to rename a file and checks for errors:
Function RenameFile(sFromLoc as String, sToLoc as String) Name sOldLoc To sNewLoc 'Check for errors Select Case Err Case 0' All is well, the file was renamed. Case 5 'Illegal Function Call MsgBox "Error " & Str$(Err) & ":" & " " & Error$ & " occurred." Case 68 'Device Unavailable MsgBox "Error " & Str$(Err) & ":" & " " & Error$ & " occurred." Case 70 'Permission Denied MsgBox "Error " & Str$(Err) & ":" & " " & Error$ & " occurred." Case 71 'Disk Not Ready MsgBox "Error " & Str$(Err) & ":" & " " & Error$ & " occurred." Case 75 'Path/File Access Error MsgBox "Error " & Str$(Err) & ":" & " " & Error$ & " occurred." Case 76 'Path Not Found MsgBox "Error " & Str$(Err) & ":" & " " & Error$ & " occurred." Case Else MsgBox "Error " & Str$(Err) & ":" & " " & Error$ & " occurred." End Select RenameFile = Err End Function Usage: Dim sOldFile As String Dim sNewFile As String Dim iRet As Integer sOldFile = "C:\PROJECTS\PROJECT1\REPORT.TXT" sNewFile = "C:\PROJECTS\PROJECT1\REPORT.TXT" iRet = RenameFile(sOldFile, sNewFile) If iRet = 0 Then 'OK to continue...
This function removes a directory from the hard drive. The following example removes a directory from the hard disk and checks for errors. The function returns the error code:
Function RemoveDirectory(sDirName as String) Dim sDirName as String 'Remove the directory RmDir sDirName 'Check for errors Select Case Err Case 0' All is well, the directory was removed. Case 68 'Device Unavailable MsgBox "Error " & Str$(Err) & ":" & " " & Error$ & " occurred." Case 70 'Permission Denied MsgBox "Error " & Str$(Err) & ":" & " " & Error$ & " occurred." Case 71 'Disk Not Ready MsgBox "Error " & Str$(Err) & ":" & " " & Error$ & " occurred." Case 75 'Path/File Access Error MsgBox "Error " & Str$(Err) & ":" & " " & Error$ & " occurred." Case 76 'Path Not Found MsgBox "Error " & Str$(Err) & ":" & " " & Error$ & " occurred." Case Else MsgBox "Error " & Str$(Err) & ":" & " " & Error$ & " occurred." End Select RemoveDirectory = Err End Function Usage: Dim sDirName as String Dim iRet as Integer sDirName = "C:\PROJECTS\PROJECT1" iRet = RemoveDirectory(sDirName) If iRet = 0 Then 'OK to continue
This function returns the current directory. Imagine that the currently selected path on drive C is C:\PROJECTS, and on drive D it is D:\GAMES. The following examples denote the uses of this function:
This statement deletes a file from the disk. Use RmDir to remove a directory. This statement accepts wildcards thus deleting multiple files at the same time. For example:
Kill "C:\PROJECTS\DEADFILE.TXT" |
Deletes the file "C:\PROJECTS\DEADFILE.TXT" |
|
|
Usage:
Dim sFile As String sFile = "C:\PROJECTS\PROJECT1\REPORT.TXT" Kill sFile If Err = 0 Then 'OK to continue...
Files can be opened and closed programatically from Visual Basic. The following section outlines the functions used in opening and closing files as well as the modes in which they can be opened. Examples are provided for each of the statements and
functions where appropriate.
This statement opens a file. There are several modes for which a file can be opened (discussed below). The syntax for the Open statement is
Open sFileName for Mode [Access sAccess] [Lock sLockParam] as iFileNum [Len = _iRecordLength]
There are several components of this statement.
If the file in the Open statement does not exist and you are using Append, Output, Random, or Binary mode, the file is created. For example, if you open the file C:\WINDOWS\ SYSTEM\MYFILE.TXT and it does not exist, an empty file with that name is
created and opened.
The following sections fully explain each of the parameters of the Open statement
The file mode is the manner in which the file is opened. Depending upon the type of operation you are performing (reading a file, writing to a file, and so on), the file is opened in a different mode. Visual Basic supports the following file modes:
Input, Output, Random, and Binary. The following lists these modes:
Input
Sequential data input. This statement is used when you want to read data from a file. It sequentially reads the number of characters in RecLen each time the file is accessed.
Output
Sequential data output. This statement is used when you want to write data to a file. It sequentially writes the number of characters in RecLen each time the file is accessed.
Random
Binary
Binary file access is used when you want to move to a certain position in the file to retrieve or write data. For example, if you know that the data you are seeking is at position 256, open the file in Random mode, seek position 256, and read the data
into your buffer using the Get statement. Data is placed into a binary file using the Put statement.
Append
The Append statement is used when you want to write data to a file and add it to the data that already exists in that file. New data is added (appended) to the bottom of the existing data. Use the Print# or Write# statements to add data to files opened
in append mode.
The Access statement decides the permissions you have when opening a file. This is a commonly ignored but very important parameter. The possible parameters are Read, Write, and Read Write. Read Write is only valid for files opened for random or binary
files opened in Append mode.
Imagine you are opening a file to read some data that your program requires. You do not need to write any data to the file. Imagine you use the following code to read from the file:
Dim iFileNum as Integer Dim sFileName as String Dim sTemp as String iFileNum = FreeFile sFileName = "C:\PROJECTS\MYFILE.TXT" 'Open the file Open sFileName for Input as iFileNum 'Keep going until the end of file is encountered Do Until EOF(iFileNum) Line Input #iFileNum, , sTemp 'Do some checking ... Loop
If your file is 100 lines long, and that after 56 lines, your program encounters a GPF (this could never happen). The first 56 lines of the file that you were reading have been erased. This is because you opened the file for read and write. When the
data was read into the sTemp variable, it was removed from the file. Solve this dilemma by opening the file for read only.
Open sFileName for Input Access Read as iFileNum
In this case you have opened the file for read only. You are still able to read data from the file and place it into the sTemp variable, but you are not endangering the source file if an error occurs. Additionally, other processes can read from this
file at the same time without encountering an error. When you open a file as writable, you are "hogging" the file and no other Windows processes or applications can open it (even for read only).
Even though the file is opened as read only, you are still able to manipulate the data that is read into the sTemp variable for use within your Visual Basic application. If you need to modify data that is read from a file and then place it back into the
file, you should open the file as writable. For example, imagine that you do the following (this is for example only, please don't do it):
This operation has just erased the entire contents of the file and replaced it with the one line you modified. In this case, it would have been much simpler to open the file as writable, read the entire file into an array using Line Input, modify the
desired array element (line of the file) and then write the entire array back into the file (first close the file and then open it in the output mode).
The Lock statement is somewhat like the Access statement except that it sets permissions that other operations have for the opened file. The options are:
The difference between this statement and the Access statement is that you can restrict access to a file for other processes even if you open the file as read only.
This example opens a file for input and locks the file for both reading and writing (no other processes can read or write to the file until it is closed using the Close statement.)
Open sFileName for Input Lock Read Write as x
The FreeFile function allocates a new file handle. This file handle is then used to open a file. The usage is as follows:
Dim iFileNum As Integer Dim sFileName As String sFileName = "C:\PROJECTS\PROJECT1\REPORT.TXT" iFileNum - FreeFile Open sFileName for Input as iFileNum
You can use literal numbers for file handles (Open sFileName for Input as 1), but it is not recommended. This can cause conflicts if you are opening several files (if you open a file as 1, forget to close it, and try to open another file as 1, you will
get an error).
The record length variable is used when you want to specify the number of characters read in each time the file is accessed. If the file is opened in Random mode, this value is the record length. For sequential files, this is the number of characters
placed in the buffer variable. For example:
File opened in Random mode with a Record Length of 40 Dim iFileNum As Integer Dim sFileName As String sFileName = "C:\PROJECTS\PROJECT1\REPORT.TXT" iFileNum = FreeFile Open sFileName for Random as iFileNum Len = 40 File opened in Input mode (Input and Output are sequential modes) with a record length of 256 Dim iFileNum As Integer Dim sFileName As String Dim sTemp as String * 256 sFileName = "C:\PROJECTS\PROJECT1\REPORT.TXT" Open sFileName for Input as iFileNum Len = 256 Input #iFileNum, ,sTemp
In this case, sTemp is 256 characters long so that is the number of characters read into the variable each time the file is accessed.
This statement closes a file. Close takes one parameter, the file handle. This is the handle that was created with the FreeFile function and was used to open the file. In the following example, iFileNum is the file handle.
Close iFileNum
Multiple parameters can be used with this statement.
Close iFileNum1, iFileNum2, iFileNum3
If no parameter is used, all open files are closed. The Close statement releases all buffer space utilized by Visual Basic when the file was open.
The Reset statement closes any open files and writes the contents to disk. This statement operates the same as the Close statement without parameters.
Most of the operations on files involve the reading and writing of data. Files can also be used as databases to store information. The following section describes the functions and statements used to read from and write data to files.
The Get statement is used to read data from a file and place it into a variable. The Get statement has the following syntax:
Dim iFileNum as Integer Dim sData as String iFileNum = FreeFile Get #iFileNum, [iRecordNumber], sData
Depending on the mode for which the file is open, either iRecordNumber or sData is used to store the data that is read from the file. If sData is a variable length string, a 2-byte descriptor with the string length is placed in sData followed by the
data. See the Visual Basic help topic "Get Statement" for additional detail on this statement.
If you choose to omit iRecordNumber, the commas must still be used.
Dim iFileNum as Integer Dim sData as String Get #FileNum, , sData
The Put statement writes the data from a variable into a file. This statement has the same parameters as the Get statement.
Dim iFileNum as Integer Dim sData as String sData = "This is a chunk of data being written to a file" Put #FileNum, [iRecordNumber], sData
In this case, the data in sData is written to the file opened using the Open statement. This file is specified after the # (in this case #iFileNum.) This writing begins in one of the following positions within the file:
If you choose to omit iRecordNumber, the comma must still be used.
Dim sData as String Put #FileNumber, , sData
See the Visual Basic help topic "Put Statement" for additional information.
The Input statement and function are used to read data from a file and assign it to a variable. Use the Input function only for files opened in Input or Binary mode. The difference between the Input statement and the Input function is that the Input
function returns all characters read from the file. This includes carriage returns, line feeds, quotes, and leading spaces. The following is the syntax for the Input function:
Dim iFileNum As Integer Dim sFileName As String Dim iLen As Integer Dim sData As String 'Number of characters to read from file Dim iChars As Integer iFileNum = FreeFile sFileName = "C:\PROJECTS\DATA.TXT" Open sFileName for Input as iFileNum iLen = LOF(iFileNum) 'If the file is less than 32000 characters, set iLen to the file size. Otherwise set it to 32000 If iLen < 32000 Then iChars = LOF(iFileNum) Else iChars = 32000 End If 'Input Function - get 32000 bytes and read it into sData sData = Input iChars, #iFileNum,
The Input function reads 32,000 characters into the variable sData. This data includes carriage returns, line feeds, and so on.
The implementation of the Input statement is the same with the exception of the following line:
Input #x, sData
This statement reads the contents of the file without leading spaces, carriage returns, line feeds, and so on.
This statement reads a line at a time from a file. The end of a line is determined when a carriage return—Chr(13) or carriage return and line feed combination—Char(13) & Chr(10) is reached. The carriage return and/or line feed is not a
part of the string that is read into the sString variable.
The syntax for this statement is as follows:
Dim sData as String Line Input #iFileNum, sData
This statement places the next line of the file into the variable sData.
The Print # statement writes data out to a sequential file. An example of when this statement is used is for the creation of a report. The following is the syntax of the Print # statement:
Dim iFileNum as Integer Dim sData as String sData = 'This is a string of data being written to a file using the Print # statement" iFileNum = FreeFile Print #iFileNum, sData
The following statement prints a blank line to the file:
Print #iFileNum,
If you are formatting data for a report, you can insert tabs and spaces so that the data is output in the correct manner. Remember to trim any leading and trailing spaces for data so that the tabs align correctly. The following line prints two columns
(Name and Address) on the same line. The columns are separated by a tab.
Print # iFileNum, "Name"; Tab ; "Address"
The following line separates the Name and Address columns with two tabs.
Print # iFileNum, "Name"; Tab(2) ; "Address"
This line is the same as above, except it places 10 spaces before the Name field.
Print # iFileNum, Spc(10) ,"Name"; Tab(2) ; "Address"
This line writes the words "Have," "a," "Nice," and "Day" to the file. each word is separated by a space.
Print # iFileNum, "Have" ; " " ; "a" ; " " ; "Nice" ; " " ; "Day"
This final example writes the words "I love file I/O" to the file preceding by five tabs.
Print # iFileNum, Tab(5) ; "I love file I/O"
Data that is output using this statement is formatted for display, so the following rules apply:
When reading and writing data to files, it is important to be able to set where in a file that operation is to take place. The following section details the functions and statements available in Visual Basic 4.0 for setting and retrieving the current
position in a file. Examples are provided where appropriate.
Because I present the EOF function, I should explain that there is no BOF function used in Visual Basic file I/O. This function is used solely with databases to locate the first database record within a file.
This is a function that returns a Boolean (true or false) value that determines whether the file pointer has reached the end of the file. The following example demonstrates the usage of this function:
Dim sFileName as string Dim iFileNum as Integer iFileNum = FreeFile sFileName = "C:\PROJECTS\PROJECT1\REPORT.TXT" 'Open the file Open sFileName For Input As #iFileNum. 'Perform the following statement until the end of file has been reached. Do While Not EOF(iFileNum) 'Read in a line from the file and place it in sData Line Input #iFileNum, sData Loop 'Close the file Close #iFileNum
This function returns the size of a file in bytes that has been opened using the Open statement.
The following example demonstrates the use of the LOF function:
Dim sFileName as string Dim iFileNum as Integer iFileNum = FreeFile sFileName = "C:\PROJECTS\PROJECT1\REPORT.TXT" 'Open the file Open sFileName For Input As #iFileNum 'Place the length of the file into the FileLength variable FileLength = LOF(iFileNum) 'Close the file Close #iFileNum
If you want to know the length of a series of files and do not need to perform I/O, use the FileLen function, covered later in the chapter.
This function returns the current position of the file pointer within a file opened with the Open statement. The usage of this function is:
Dim sFileName as string Dim iFileNum as Integer iFileNum = FreeFile sFileName = "C:\PROJECTS\PROJECT1\REPORT.TXT" Dim sData as String * 256 Dim iPos as Integer 'Print the current file position to the form (before we start reading the file.) Form1.Print "The current file position is: " & iPos Do While iPos < LOF(iFileNum) 'Grab 256 characters from the file and place into sData sData = sData & Input(256, #1) 'Get the new file position iPos = Loc(iFileNum) Form1.Print "The current file position is: " & iPos Loop Close #1 ' Close file.
The Seek statement and function set and get the current position within a file. The file must have been opened using the Open statement. The Seek statement sets the position for the next read from or write to the open file. The following example opens a
file for random and reads all the records into a variable. A record is comprised of a Customer type structure.
First we define a type called customer. This is done in the general declarations section of a module.
Type Customer sName As String * 30 sAddress As String * 60 iPurchases as Integer End Type
Next, we create the function that reads the file.
Sub ReadCustomerFile Dim sFileName as String Dim i as Integer Dim iFileNum as Integer Dim iMax as Integer Dim tRecord() As Customer iFileNum = FreeFile sFileName = "C:\PROJECTS\PROJECT1\REPORT.TXT" ' Open the file Open sFileName For Random As iFileNum Len = Len(tRecord) 'The next statement gets the number of records in the file iMax = LOF(iFileNum) \ Len(tRecord) ' Read the records in the file and place them into the sData array For i = 1 To Max Seek #1, RecordNumber ' Set position. ReDim Preserve tRecord(i) Get #1, , tRecord(i) Next i Close iFileNum
For modes other than Random, Seek sets the position in the file where the next operation takes place.
Visual Basic 4.0 offers a variety of statements and functions for getting information about files. This section covers those and provides examples where necessary.
This function returns the name of a file meeting the specifications of the parameter passed to it. This function requires a path and allows the use of wildcards. One of the most useful places for this function is when you would like to gather a list of
all files in a directory.
The following example creates a list of all files in the C:PROJECTS\PROJECT1 directory. Each file in the directory is added to the sDirList array. This listing includes all files in the directory.
Dim sDirectory as String Dim sFile as String Dim i as Integer Dim sDirList() as String sDirectory = "C:\PROJECTS\PROJECT1" sFile = Dir$(sDirectory & "\*.*") i = 0 Do While Len(sFile) ReDim Preserve sDirList(i) sDirList(i) = sDirectory & "\" & sFile sFile = Dir$ i = i + 1 Loop
This function can be modified to include only the Microsoft Word document (.DOC) files by changing one line.
sDirectory = "C:\PROJECTS\PROJECT1\*.DOC"
Additionally, this function has an attributes argument that allows you to specify the following file types:
Constant |
Value |
Description |
vbNormal |
0 |
Normal files |
vbHidden |
2 |
Hidden Files |
vbSystem |
4 |
System Files |
vbVolume |
8 |
Volume Label (all other attributes are ignored if this is used) |
|
|
|
The example is modified to screen for Hidden Files only.
Dim sDirectory as String Dim sFile as String Dim i as Integer Dim sDirList() as String sDirectory = "C:\PROJECTS\PROJECT1" sFile = Dir$(sDirectory & "\*.*", 2) '<< Hidden Files Only i = 0 Do While Len(sFile) ReDim Preserve sDirList(i) sDirList(i) = sDirectory & "\" & sFile sFile = Dir$ i = i + 1 Loop
The FileAttr function provides two types of information about a file opened from Visual Basic using the Open statement. This function returns either the mode for which the file was opened, or the operating system file handle (not the Visual Basic file
number retrieved using FreeFile). The syntax is as follows:
Dim iFileNum as Integer Dim sFileName as String Dim iMode as Integer Dim iHandle as Integer iFileNum = FreeFile sFileName = "C:\PROJECTS\PROJECT1\REPORT.TXT" Open sFileName for Output as iFileNum 'Get the mode for which the file is opened iMode = FileAttr(iFileNum, 1) 'Get the operating system file handle for the open file iHandle = FileAttr(iFileNum, 2)
The modes are as follows:
Mode |
Value |
Input |
1 |
Output |
2 |
Random |
4 |
Append |
8 |
|
|
In using this function, it is a good idea to establish global constants for each of the values. The following example declares global constants for each of the modes and places the FileAttr call into a function:
Global Const gcI_Input = 1 Global Const gcI_Output = 2 Global Const gcI_Random = 4 Global Const gcI_Append = 8 Global Const gcI_Binary = 16 Function GetFileInfo(sFileName as String, iInfoType as Integer) Dim iMode as Integer Dim iHandle as Integer 'Get the mode for which the file is opened iMode = FileAttr(iFileNum, 1) 'Get the operating system file handle for the open file iHandle = FileAttr(iFileNum, 2) End Function 'The function is called in this manner: Dim sFileName as String Dim iRet as Integer Dim iHandle as Integer sFileName = "C:\PROJECTS\PROJECT1\REPORT.TXT" iRet = GetFileInfo(sFileName, 1) 'Check to make sure that the file is opened in the correct mode. Using global constants makes the code 'more readable If iRet <> gcI_Input then MsgBox "File opened in incorrect mode" End If iHandle = GetFileInfo(sFileName, 2)
This function returns the length of a file in bytes. This operation is performed on a closed file. If the file is open, use the LOF function. This function can be used to add up the size of all files you choose to include so that you are sure of the
total size. Additionally, the FileLen function is a good compliment to any status that you are providing to a user. For example, if you have 50,000 bytes of files to process, you can determine how far along you are after each file is completed. This can be
passed to the gauge control.
The syntax for the FileLen function is as follows:
Dim iRet as Integer Dim sFileName as String sFileName = "C:\PROJECTS\PROJECT1\REPORT.TXT" iRet = FileLen(sFileName)
This function is also useful in combination with the Dir function to get the size of all files selected. You modify your Dir function example.
Type DirInfo sFileName as String iFileSize as Integer End Type Dim sDirectory as String Dim sFile as String Dim i as Integer Dim sDirInfo() as String sDirectory = "C:\PROJECTS\PROJECT1" 'Get all files in the directory and place them into sDirInfo(). sFile = Dir$(sDirectory & "\*.*" ) i = 0 Do While Len(sFile) ReDim Preserve sDirList(i) sDirInfo(i).sFileName = sDirectory & "\" & sFile sDirInfo(i).iFileSize = FileLen(sDirectory & "\" & sFile) sFile = Dir$ i = i + 1 Loop
The FileDateTime function returns a file's last modification date and time. If this file has not been modified, the return is the file creation date and time. The following builds on our FileLen example and adds the file date and time to the array of
directory information:
Type DirInfo sFileName as String iFileSize as Integer iFileDateTime As Variant End Type Dim sDirectory as String Dim sFile as String Dim i as Integer Dim sDirInfo() as String sDirectory = "C:\PROJECTS\PROJECT1" 'Get all files in the directory and place them into sDirInfo(). sFile = Dir$(sDirectory & "\*.*" ) i = 0 Do While Len(sFile) ReDim Preserve sDirList(i) sDirInfo(i).sFileName = sDirectory & "\" & sFile sDirInfo(i).iFileSize = FileLen(sDirectory & "\" & sFile) sDirInfo(i).iFileDateTime = FileDateTime(sDirectory & "\" & sFile) sFile = Dir$ i = i + 1 Loop
Now that we have covered the basics of file I/O using Visual Basic, it is time to move on to more advanced concepts. The next section of this chapter covers methods of searching a file for information, creates a database using a binary file, and delves
into the realm of binary trees and binary chops.
Now that you have opened and read data from a file, it's time to search for something. First take this from a text file point of view.
Imagine that you have a file listing the names and addresses of all employees in a company. A section of the file may look like this:
As you can see, this file is not formatted into defined fields. Imagine that you are searching this file for Steve Jones. The following example searches the file and returns the record number:
Function GetRecordNumber(sLastName as String) Dim iFileNum as Integer Dim sFileName as String Dim sTemp as String Dim I as Integer Dim iPos as Integer Dim iFound as Integer sFileName = "C:\PROJECTS\PROJECT1\EMPLOYEE.TXT" iFileNum = FreeFile Open sFileName for Input Access Read as iFileNum Do Until EOF(iFileNum) Line Input #iFileNum, sTemp 'Record Number Counter I = I + 1 iPos = Instr(sTemp, sLastName) 'If we find the name, set iFound to true If iPos Then iFound = True Exit Do End If Loop Close iFileNum If iFound = True Then GetRecordNumber = I Else GetRecordNumber = 0 End If End Function
This example returns the record number that holds the information. The example can be modified to return any element of information contained in the line.
First, review your data:
You are interested in getting the zip code from the customer record. Once you have the line of data from the file in sTemp, do the following:
Dim iZipCode as Integer iZipCode = Right$(sTemp, 5)
This assumes that the zip code has five positions. If not, we have gotten incorrect data. A better implementation searches for the first space in the string starting from the right. Anything to the right of this space is the zip code. We trim the string
first to ensure that there are no leading spaces.
Dim iZipCode as Integer Dim iLen as Integer Dim iFoundSpace 'Get rid of leading and trailing spaces. sTemp = Trim$(sTemp) 'Get the length of the line and place it in iLen iLen = Len(sTemp) 'Start at the rightmost character in the string searching for a space. step backwards 1 space at a time. For I = iLen to 1 Step -1 iPos = Instr(Mid$(sTemp,I, 1), " ") If iPos Then iFoundSpace = True End If Exit For Next I 'Once we find the space, set the characters to the right of the space to the zip code (iPos - 1 ensures that we do not include the space in iZipCode) If iFoundSpace = True Then iZipCode = Right$(sTemp, iPos - 1) End If
Now, let's put it all together. The complete function searches for a last name in the list. It returns the record number, a space, and then the zip code.
Function GetRecordNumber(sLastName as String) Dim iFileNum as Integer Dim sFileName as String Dim sTemp as String Dim I as Integer Dim iPos as Integer Dim iFound as Integer Dim sZipCode as Integer Dim iLen as Integer Dim iFoundSpace sFileName = "C:\PROJECTS\PROJECT1\EMPLOYEE.TXT" iFileNum = FreeFile Open sFileName for Input Access Read as iFileNum Do Until EOF(iFileNum) Line Input #iFileNum, sTemp 'Record Number Counter I = I + 1 iPos = Instr(sTemp, sLastName) 'If we find the name, set iFound to true and get the zip code. If iPos Then iFound = True 'Get rid of leading and trailing spaces. sTemp = Trim$(sTemp) 'Get the length of the line and place it in iLen iLen = Len(sTemp) 'Start at the rightmost character in the string searching for a space _and step backwards. For I = iLen to 1 Step -1 iPos = Instr(Mid$(sTemp,I, 1), " ") If iPos Then iFoundSpace = True End If Exit For Next I 'Once we find the space, set the characters to the right of the space to the _zip code (iPos - 1ensures that we do not include the space in iZipCode) If iFoundSpace = True Then sZipCode = Right$(sTemp, iPos - 1) End If Exit Do End If Loop Close iFileNum 'If we found the record, return the record number and the zip code If iFound = True Then GetRecordNumber = I & " " & sZipCode Else 'We did not find the record GetRecordNumber = 0 End If End Function
The section above demonstrated the reading and searching of a text file for information. Although this is possible, it is not the most efficient method of data storage. As you saw from the example above, it is clearly not the easiest to manipulate. This
section discusses the structured use of binary files for the storage and retrieval of data.
The section above demonstrated a rather crude database. In this section, you use the same data but store this data in a more organized format. Start with the data
First, create a structure in which to store the data.
Type CustomerRecord sFirstName as String * 20 sLastName as String * 20 sAddress as String * 50 sCity as String * 10 sState as String * 2 sZipCode as String * 5 End Type
As you can see, this is a much more organized method of data storage. Next implement the program that adds records to the database. This assumes that the data has already been placed into the tCustomer structure by the user (added entering information
into text boxes and clicking a command button, and so on).
Function AddRecord(sFileName as string, tCustomer as CustomerRecord) Dim iFileNum as Integer Open sFileName for Append as iFileNum Print # iFileNum, tCustomerRecord Close iFileNum End Function
Remember that rather large function in the last section used to search the file for information? Implement the function again using the new file format. In this case, the following parameters are passed to the function:
Function GetRecord(sFileName as String, sLastName as String, tCustomer as tCustomerRecord)
Dim iFileNum as Integer Dim tTemp as tCustomerRecord Open sFileName for Input Access Read as iFileNum Len=Len(sCustomer) Do Until EOF(iFileNum) Get # iFileNum, tTemp 'Do the compare. Uppercase and trim each string so that the comparison _works. If UCase(Trim$(tCustomerRecord.sLastName)) = UCase(Trim$(sLastName)) Then iFound = True Exit For Endif Loop Close iFileNum 'If we found it, place the data from the database into the tCustomer structure _which was passed into the function. If iFound = True Then tCustomer = tTemp Endif End Function
As you can see, this is a much simpler function, and because you are not manipulating strings with Instr and Trim$, there is less chance for error. Each piece of information is stored in an element of the structure.
Now that you have implemented a more structured method of storing and retrieving data, take it one step further. Let's review:
You now have a database that is comprised of type structures containing customer information. The structure is as follows:
Type CustomerRecord sFirstName as String * 20 sLastName as String * 20 sAddress as String * 50 sCity as String * 10 sState as String * 2 sZipCode as String * 5 End Type
You write all the records to a file using this structure as a format. When you want to search for a record (using the last name for example), you read the records from the file into a temp structure and check to see if Temp.LastName is equal to what
you are searching for. This is fine if the database contains a limited number of records, but what if the database contains 100,000 records? This process is slow because each record must be compared to the desired last name to see if there is a match.
Additionally, if Trim$ or Instr are used, the process is slowed further.
An alternative to this is to sort the records in the file and then search them. However, this does not increase the speed of the search because every record must still be checked. The answer to this dilemma is what is termed a binary chop.
Imagine that you have an array of 100 elements. The binary search method is structured as follows:
Divide the array by 2 to find the center and assign that value to iIndex. In the example, 100 elements / 2 = 50. Therefore, iIndex = 50. This is the place to start searching for the record.
Create 2 variables: iLBound - This is equal to the lowest element in the array or LBound(Array) iUBound - This is equal to the highest element in the array or UBound(Array)
Start searching the array at position iIndex (50). If what you are looking for is less than the value of the center element (in this case number 50) then you know that element number 50, as well as all elements with an array index greater than 50 are
not the one that you are looking for. An example: Imagine that you are searching for c and that the center element is n. Because c is less than n, you know that n, and any item with an array index greater than n is not what you are looking for. Therefore,
all elements of the array 50 and above are eliminated. To eliminate the elements, change iUBound to iIndex - 1. The -1 eliminates element number 50 from the remaining eligible elements.
If what you are searching for is greater than the center element (iIndex), then you know that the center element and all elements with an array index less than it are eliminated, so we change iLBound to iIndex + 1.
Imagine that you have the following array :
0 |
A |
1 |
B |
2 |
C |
3 |
D |
4 |
E |
5 |
F |
6 |
G |
7 |
H |
8 |
I |
9 |
J |
10 |
K |
Now, imagine that you are searching for the element "C."
Do the following:
As far as your program is concerned, this array now only has five elements to search:
0 |
A |
1 |
B |
2 |
C |
3 |
D |
4 |
E |
5 |
F |
This results in 2. Therefore, the center of your array is now element number 2. Start the process over again. Look at element 2 and find the letter C. Because what you are searching for is greater than B, you know that element 1 and any element less
than 1 (just 0 in this case) are not what you are looking for. Then reset the iLBound variable to 2. As far as your program is concerned, the array now is:
2 |
C |
3 |
D |
4 |
E |
|
|
When there is an even number of elements in the array it can't be exactly split in half so you must remember to use CInt when calculating the index. In this case, it makes no difference if iIndex ends up at element 3 or 4. In either case, one more
iteration of the loop is necessary to find the entry that you are searching for.
So... you searched a 10-element array with only four iterations to find what you were looking for. You accomplished the same task but took only 60% of the time to do it. In many cases this percentage will be as low as 33%. This is a very effective
method not only for file I/O, but for array searching in general.
The following program fully implements the binary chop function. When an item is found, its count is incremented. This function uses a typed array with a structure as follows:
Type Customer LastName as String iHits as Integer End Type Dim sArray as String 'LBound and UBound variables iLBound = LBound(sArray) iUbound = UBound(sArray) 'Keep going until either iLBound and iUBound are equal, or until iLBound is _greater than iUBound (no more elements to search). Do Until iLBound >= iUbound 'Reset the iIndex variable each time through the loop (since the array _is 'smaller') iIndex = CInt((iUbound + iLBound) / 2) 'Compare what we are searching for to the array entry iVal = StrComp(sSearchFor, sArray(iIndex).LastName) Select Case iVal Case -1 'What we are searching for is less than the array _element iUbound = iIndex - 1 Case 0 'We have found what we are searching for. Increment the _counter and exit the loop. sArray(iIndex).iHits = sArray(iIndex).Hits + 1 Exit For Case 1 'What we are searching for is greater than the array _element. iLBound = iIndex + 1 End Select Loop
Now that you know the basics of file I/O from Visual Basic, you should know that many of the files on your system can be opened and read if the proper file format is known. The format for a C language type structure is:
typdef struct tag TYPENAME { int formatID; char lenData[50]; char offData[65]; int formSize; }TYPENAME;
With a very small amount of work (mostly understanding variable type conversions), these formats can be applied to Visual Basic.
Type TYPENAME formatID as Integer lenData as String * 50 offData as String * 65 formSize as Integer End Type
This book provides you with an understanding of the structure of many files formats, including
Icon files |
.ICO |
Font files |
.FNT |
Windows metafiles |
.WMF |
Clipboard view files |
.CLP |
|
|
All these files can be opened from Visual Basic with the routines outlined in this chapter.
Additionally, when creating files for your application that you will access at a later time, it is important to ensure that you are accessing the correct file. Microsoft recommends that the first four bytes of your file contain information identifying
the file as yours (this can be anything that you deem desirable. When accessing the file, ensure that you have the correct file by checking the first four bytes. The following example opens a Visual Basic 3.0 module and checks to see whether the file is
saved as text. If it is, it is okay to continue.
Dim sFileName as String Dim iFileNum as Integer Dim sByte As String * 1 iFileNum = FreeFile sFileName = "MODULE1.BAS" Open sFileName For Binary Access Read As IFileNum Get #iFileNum, , sByte If sByte = Chr$(&HFC&) Then iRet = MsgBox("This module is saved in binary format.", 36, "Visual Basic 4 Unleashed") ElseIf sByte = Chr$(&HFF&) Then iRet = MsgBox("This module is saved in text format.", 36, "Visual Basic 4 Unleashed") End If Close iFileNum
This chapter covered the basics of file input and output (I/O) in Visual Basic. First, the basics of file input and output (I/O) were covered. This included the functions and statements that Visual Basic provides for the opening, closing, and
manipulation of files. This was followed by more advanced topics including the reading of files in blocks, binary chops, and file formats.