Hour 21


During this hour you will learn

Accessing Files

This lesson explains the fundamentals of file I/O. Although professional VB programmers don't use the file I/O commands you'll learn in this lesson (because they generally work with the more flexible data and database controls that you'll master later), all programmers should understand file fundamentals and should understand every concept in this lesson before using those other database tools.

You'll learn all about the kinds of file processing possible and the commands that VB supports to work with such processing. At the core of every advanced file I/O routine and database control lie the fundamental concepts you'll learn this hour.

Three file types exist: sequential, random, and binary. Sequential access is the simplest file access, but prone to some drawbacks; although sequential files are simple to create and read, they can be slow and cumbersome. Random access is a much faster and more useful method of access, but programs that use random-access files are often more complex than sequential-access programs. Binary files are special, compacted forms of random-access files. (Binary files are difficult to work with but are discussed briefly in Hour 22, "Adding OLE to a Program.")

Like random-access memory, you can access random-access files in any order. Random-access files work with any kind of data you can declare. When you learn how to declare user-defined data types at the end of this hour, you'll be able to use the Put # command to write (or read) an entire set of information to (or from) a data file in one statement.

Topic 1: Basic File-Handling Concepts

Virtually every program in existence today uses files. At the very least, even if a program doesn't use files, the program itself is a file that executes when users run the program. Whether a program saves data into a database or just keeps information for its own use (such as a user's preferred color scheme or window position), most programs do rely on files.

FAST TRACK
If you understand flat-file processing concepts, you can skip to Hour 22, "Adding OLE to a Program".

Overview

Several Visual Basic commands are common to all forms of file input and output. These commands open the files, specify the file modes, close the files, and check for free file numbers to be used as file associations. This topic section explains how fundamental file processing operates. One of the ways you can better understand file concepts is to begin with the first statement of any file-based project: the Open statement.

The Open Statement

Sequential files and random-access files share common features. You use Open for both file types. The kind of file access you achieve with Open depends on the arguments you use in the Open statement.

Open initiates a channel for reading from and writing to a file. When this channel is open, the data stream can flow. The mode for which you open the channel-read, write, or both-dictates how the data stream can flow between the file and the computer.

Here is the Open statement's syntax:

Open strFileName [For Mode] [AccessRestriction] [LockType] As [#]Channel% [Len = intRecordLength]

The Channel value is commonly called the file number or file handle. When you open a program and assign a data file to a number, the program will use that file number to access that file. Your program never again has to use the file name to get to the file. This chapter refers to the channel value and file number interchangeably because of their common uses in the data-processing industry.

All Open statements must include the file-name and file-number arguments, but the other arguments are optional. A simple call to Open with only the required parameters might look like this:

Open "aFile.Txt" As #1

This statement opens a file named aFile.Txt as file number 1. To reference this file for input or output, you reference the file number. This file has been opened in random access mode, because the default when you omit the For Mode portion is Random. All of this lesson's commands work with text files. This lesson uses the file-name extension .txt or .dat, two commonly used extensions for text files.

The Modes

Table 21.1 explains the optional settings for Mode values.

Table 21.1 Open Statement Modes

Mode

Description

Append

Opens a file number to a file for sequential output, beginning at the end of the file if the file exists. If the file doesn't exist, VB creates the file. Append never overwrites existing files.

Binary

Opens a file number to a file for binary data access. In Binary mode, you can access a file at the byte level, meaning that you can write and read individual bytes to and from the file.

Input

Opens a file number to a file for sequential input, starting at the beginning of the file. Data is read in the same order that it was sent to the file.

Output

Opens a file number to a file for sequential output, starting at the beginning of the file. If the file doesn't exist when you issue the Open statement, VB creates the file; otherwise, VB overwrites the file.

Random

Opens a file number to a file for random read and write access. This mode allows data to be read from and written to a file at any specific record boundary.

For Mode isn't required when using the Open statement. If you don't include the mode, Visual Basic assumes Random and inserts the For Random mode for you. The following examples show how to use various modes for opening a file:

Open "filInpdt.txt" For Input As #1

Open "Append.txt" For Append As #1

Open "Output.txt" For Output As #1

Open "Random.txt" For Random As #1

The last statement is equivalent to the following:

Open "Random.txt" As #1

Be sure to set up error-handling logic using the On Error Goto statement that you learned about in Hour 17. Any time you open or access a file, an error might result. Good error-handling logic will help your application exit gracefully from the problem rather than burden users with nasty runtime error messages.

AccessRestriction

The optional AccessRestriction in an Open statement lets you restrict the access to Read, Write, or Read Write. This access restriction is often used when writing programs that will run across a network.

Specifying read-only access with Read lets users see the contents of the file, but leaves them unable to modify the file. Specifying Write access lets users modify the file, and specifying Read Write lets users do both (read and modify).

LockType

Use a LockType to specify the operations permitted on the open file by other processes. This parameter is useful when writing network applications. You can restrict access to a file so that only one user at a time has access to the file or can write to the file. This helps prevent two users from trying to make changes at the same time (which would inevitably lose the changes that one of the users made).

The valid options for LockType are Shared, Lock Read, Lock Write, and Lock Read Write. Shared lets all users access the file simultaneously. Lock Read locks the file so that only the person with the file open for reading can access the file. Lock Write locks the file so that only the person who has the file open for write access can write to the file. Lock Read Write locks the file from all users except the one who has the file now open for read and write access.

Len = intRecordLength

The length specified by the Len = intRecordLength option is used by random-access files as the size of data records that will be passed from VB to the file. This size is necessary when accessing records from a file. The first record in a file begins at location 1, and all subsequent records are written at locations in increments of 1. The actual location in the file of any given record is N[ts]intRecordLength, where N is the record number.

This record access might seem similar to the way you access arrays. Although the first element in an array is stored in Array(0), the first element in a file is stored at record number 1. To make index coordination between arrays and files easy, use Option Base 1 in your Declarations section, or define your arrays to begin with element 1 and ignore the 0 subscript.

The FreeFile Function

Visual Basic lets you open multiple files at once, as long as you assign each file a different file number. You need to keep track of the next available number, especially if you open files in a function that has no way of knowing whether other functions have opened files. VB provides the FreeFile function, which can be used to determine the next available file number. By using this function, you're guaranteed that the file number you use hasn't already been used by an open file. Here is the syntax of FreeFile:

FreeFile[(RangeNumber)]

The optional RangeNumber parameter lets you specify that you want the returned file number to be in a specific range: 1-255 or 256-511. The default range, if you specify no RangeNumber parameter, is 1-255. Almost all Visual Basic programmers keep the default because rarely, if ever, do programs need to open more than 256 files. The following lines use FreeFile to obtain a file number and then open a file with that number:

intFileNumber = FreeFile

Open "AccPay.Dat" For Output As intFileNumber

Use FreeFile whenever you want to ensure that a file number isn't already in use. This may not be necessary for small applications that use only several files. Even in small applications, however, it helps to use FreeFile to ensure that you don't accidentally use the same file number for more than one file at a time.

Avoid the shortcut of using FreeFile within the Open statement, as shown here:

Open strFileName For Output As FreeFile
Although this works, you have no way to know the file number for later operations on the file.

The Close Statement

You need to close all files that you open with Open. The statement for closing a file is-not surprisingly-Close. This statement takes the open file number as its only parameter. The complete syntax is as follows:

Close # intChannelNumber[, intChannelNumber2][, ...intChannelNumberX]

You can specify any number of channels (file numbers) to close in a single Close statement. If you don't specify a file number, all open channels are closed. This can be useful for terminating your applications.

Example

The code in Listing 21.1 opens two sequential files-one for reading and one for writing-on the next available channels, and closes both files when done.

Listing 21.1 Using FreeFile to Request a File Number from Visual Basic

Dim intReadChan As Integer, intWriteChan As Integer

' Handle input file

intReadChan = FreeFile   ' Get first channel #

Open "AccPay.Dat" For Input As intReadChan

' Handle output file

intWriteChan = FreeFile   ' Get next channel #

Open "AccPayOut.Dat" For Output As intWriteChan

'

' Code goes here to send the contents

' of the input file to the output file

' (You'll learn how to do this later in the lesson)

Close intReadChan

Close intWriteChan

You never have to use an actual file number in this example, because FreeFile returns available channels and the code stores those values as named integers.

If you don't close all open files, you run a risk-albeit a small one today due to improved hardware-that damage will occur to the file. Generally, if power goes out when a file is open, the file's contents might be in jeopardy. Therefore, don't keep a file open longer than you need it to be open. If you don't close a file, the system closes the file when your application terminates.

Next Step

You can close as many files as you want with a single Close statement. The following simple line closes all open files:

Close

The following lines would, instead, close only two files that might be open:

Close 3

Close 6

You may want to close certain files in the middle of a program when you're finished with those files but still need access to other open files.

Topic 2: Sequential Access Files

Now that you've seen the basic statements required for opening files, closing files, and setting file-access modes, this topic section looks at several examples that output to and input from sequential access files. You'll see that a form of Print, which you used earlier for form and printer output, can output text to a file.

Overview

Sequential file access means just that-you access the file sequentially. When you create a sequential-access file, you're creating a file that your application must read from and write to sequentially (that is, in order from the file's beginning to end). This sequential read and write limitation is the biggest weakness of a sequential file.

To use the file, you must process the entire file from beginning to end. If you need to update only 1 byte of information in a 1,000-byte file, you must process 999 extra bytes every time you want to perform the update.

Sequential file access can be very useful if you need to process a text file, such as a settings file, or if you're storing small amounts of data where access speed isn't a issue. This topic section looks at the VB functions that handle sequential files.

The Print # Statement

You must open files to use them in your program. After you open the files, you must put information into them. One common approach is the Print # statement. Print # writes only to a sequential access file. Here is the syntax of Print #:

Print #intChannelNumber, [OutputList]

intChannelNumber is the open file number to which you want to write. OutputList can consist of the following:

[{Spc(intN1) | Tab[(intN2)]}] [Expression] [charPos]

The braces ({}) indicate that you can use either Spc() or Tab(), but not both together. Table 21.2 explains the components of OutputList.

Table 21.2 The Print # Statement Contents

Component

Description

Spc(intN1)

Used to insert spaces in the output, where intN1 is the number of spaces to insert.

Tab(intN2)

Used to position the insertion point to an absolute column number, where intN2 is the column number. Use Tab with no argument to position the insertion point at the beginning of the next print zone (a print zone occurs every 14 spaces).

Expression

A numeric or string expression that contains the data you want to send to the file.

charPos

Specifies the insertion point for the next character to print. Use a semicolon to specify that the next character should appear immediately following the last printed character.

You can use Tab() in charPos; the functions that Tab() performs at the beginning of a Print # statement also apply here. If you omit charPos, the next character appears on the next line in the file.

The procedure in Listing 21.2 opens a file named Print.txt, writes the numbers 1 through 5 to the file, and then properly closes the file.

Listing 21.2 Writeseq.bas: Using Print # to Write to a Sequential File

Private Sub cmdFile_Click()

  Dim intCtr As Integer   ' Loop counter

  Dim intFNum As Integer  ' File number

  intFNum = FreeFile

  ' Change the path if you want

  Open "C:\Print.txt" For Output As #intFNum

  ' Describe this proc

  Debug.Print "File Print.txt opened"

  For intCtr = 1 To 6

    Print # intFNum, intCtr    ' Write the loop counter

    Debug.Print "Writing a " & intCtr & " to Print.txt"

  Next intCtr

  Close # intFNum

  Debug.Print "File Print.txt closed"

End Sub

If you run this procedure, you see the Immediate window output shown in Figure 21.1. The procedure keeps you posted that it has opened the file, and then proceeds to write to the file and show you what has been written. Finally, the procedure closes the file and tells you that the file has been closed.

FIG. 21.1

It's easy to monitor the progress of the Print # statement.

To verify that the procedure worked, open Notepad and look at the Print.txt file. You should see the numbers 1 through 5 printed inside the file, as shown here:

1

2

3

4

5

Listing 21.2 demonstrates a simple Print # statement. No statements existed to position the output, so the procedure defaulted to printing each number on a new line. An example at the end of this topic section explains how you can embed formatting codes in the Print # command.

Creating and writing to a file won't do you much good if you can't retrieve the information when you want to. The following section covers retrieving information from a file.

The Input # Statement

After you write data to a file, you eventually will need to retrieve that data. For sequential files, use the Input # statement to read sequential data. You must read the data in exactly the same order and format as you wrote it, due to the nature of sequential file processing. Here is the syntax of Input #:

Input # intChannel, Variable1[, Variable2][, ...VariableN]

Input # requires an open file number and variables to hold the data you're reading. The Input # statement and the Print # statement that originally wrote the data to the file should use the same format. If you used comma delimiters to write the data, you should use the same delimiters for Input #.

If you write a series of variables on one line and want to be able to read them reliably with Input #, you must either use Write instead of Print #, or manually include comma delimiters. Input # reads up to the first space, comma, or end of line if it reads into a numeric variable. It reads up to the first comma or end of line when reading a string, unless the string contains quotation marks.

The following statement reads five variables from an open sequential file. The variables all reside on the same file line:

Input #intChannel V1, V2, V3, V4, V5

The Print # statement that created the file has to match the Input # statement's format and use the same variable data types; otherwise, Input # can't read the data.

Input # is fairly simple because it performs the mirror-image task of Print #. As the next section explains, Write # often outputs file data in a more general format than Print #, reducing your worry about matching the Input # statement to its original output code.

The Write # Statement

Write # is another command that writes information to a sequential file. Write # and Print # vary only slightly. All data that Write # writes to a file is comma-delimited, not space-delimited. Also, Write # automatically encloses all string data inside quotation marks (the quotation marks appear in the file), encloses all date data within pound signs, writes Boolean data as #TRUE# or #FALSE#, and sends null data and error codes to the file as #NULL# and #Error errorcode#, respectively. (errorcode represents an error number that explains the output error that has occurred, such as a disk not found.)

Comma-delimitation is required for files that certain mail-merge or spreadsheet programs read. The commas also make reading the data less error-prone because subsequent Input # statements don't have to match the Write # exactly.

To read data correctly from a file into variables, always use Write # instead of Print #.

Here is the syntax for Write #:

Write # intChannel, [OutputList]

OutputList is the list of one or more variables you want to read from the file opened on the file number.

The upcoming "Next Step" section demonstrates the use of Write #.

Example

The earlier section "The Print # Statement" showed how to output one value per line with the Print # statement. You can include the same formatting options in Print # that you can include in the regular Print method.

For example, if you want to print the values one after another on the same line, you include a semicolon after the intCtr variable, as is done in Listing 21.3.

Listing 21.3 Oneline.bas: Using the Semicolon to Write Multiple Values on a Single Line

Private Sub cmdFile_Click()

  Dim intCtr As Integer   ' Loop counter

  Dim intFNum As Integer  ' File number

  intFNum = FreeFile

  ' Change the path if you want

  Open "C:\Print.txt" For Output As #intFNum

  ' Describe this proc

  Debug.Print "File Print.txt opened"

  For intCtr = 1 To 6

    Print # intFNum, intCtr;    ' Notice semicolon!!

    Debug.Print "Writing a "; intCtr; " to Print.txt"

  Next intCtr

  Close # intFNum

  Debug.Print "File Print.txt closed"

End Sub

When you run this procedure, the created file contains the following:

1 2 3 4 5

Notice the spaces between the numbers when they're printed to the same line. Print # inserts these spaces so that the different data elements you write to the file can be distinguished from each other. This space is referred to as a delimiter. When you attempted to read the data later, it would be difficult to know how many elements were written if the file contained 12345... instead of 1 2 3 4 5 . . ..

You should experiment with the different Print # parameters to see what results you get when creating a file.

Next Step

After you write data to a file, reading back the data often takes place in another procedure-or even another application-that needs the data. The procedures in Listing 21.4 provide examples of how you can write to a file and then read the information back into variables.

Listing 21.4 Readwrit.bas: Reading and Writing to a File in the Same Procedure

Private cmdFileOut_Click ()

  ' Create the sequential file

  Dim intCtr As Integer   ' Loop counter

  Dim intFNum As Integer  ' File number

  intFNum = FreeFile

  Open "Print.txt" For Output As #intFNum

  For intCtr = 1 To 5

    Print # intFNum, intCtr;    ' Write the loop counter

  Next intCtr

  Close # intFNum

End Sub

Private cmdFileIn_Click ()

  ' Read the sequential file

  Dim intCtr As Integer   ' Loop counter

  Dim intVal As Integer   ' Read value

  Dim intFNum As Integer  ' File number

  intFNum = FreeFile

  Open "Print.txt" For Input As #intFNum

  For intCtr = 1 To 5

    Input # intFNum, intVal

    ' Display the results in the Immediate window

    Debug.Print "Retrieved a " & intVal & " from Print.txt"

  Next intCtr

  Close # intFNum

  Debug.Print "The Print.txt file is now closed."

End Sub

Figure 21.2 shows the Immediate window that appears when you run this code and click the buttons assigned to the file output and file input tasks.

FIG. 21.2

The Immediate window here monitors writing and then reading the same file.

Now look at the procedure in Listing 21.5, which creates a file named Write.txt.

Listing 21.5 Writeout.bas: Writing Output to Sequential Files

Private cmdFile_Click ()

  Dim intCtr As Integer   ' Loop counter

  Dim intFNum As Integer  ' File number

  intFNum = FreeFile

  Open "Write.txt" For Output As #intFNum

  For intCtr = 1 To 5

    Write # intFNum, intCtr;    ' Write the loop counter

  Next intCtr

  Close # intFNum

End Sub

After this procedure creates the Write.txt file, use Notepad to look at its contents. You'll immediately notice the difference between the Print # and Write # statements. Here are the contents of Write.txt:

1,2,3,4,5,

If you didn't use the semicolon after the data you wrote, each piece of data would be on its own line and no commas would separate the data, because the single value per line would make the commas unnecessary. (In that case, Write # and Print # would behave identically.)

If you use sequential files often, you'll soon gain insight into ways you can improve your code. For example, you might want to write (as the first piece of data in the file) the number of values that appear in the file, so subsequent programs that read the data will know how many values exist and can loop accordingly.

Keep in mind that VB programmers rarely use sequential file processing! You're not wasting your night-school lesson this hour, however, because all the more common file-access methods and controls use the fundamentals that sequential file processing teaches you.

Topic 3: Random-Access Files

Whereas you must read and write sequential files in order, you can read and write random-access files (often just called random files) in any order. For example, you can write customer records to a random-access file and then read one or more customer records later in any order you want. If the customer file were sequential, you would have to read every record in the file that preceded the records you wanted.

Overview

This topic section explains how to perform I/O with random-access files. As with sequential access, programmers don't use random access in its strictest form today as much as in the past because of the increased availability of data-access controls and advanced file-processing procedures. Nevertheless, most file access is based on the concepts you'll learn here.

Random-access files offer a good opportunity to learn about user-defined data types. A user-defined data type is a data type that you define and use instead of one of the built-in data types (such as Integer and String). Random-access files often read and write data records, and VB's user-defined data types let you define data items that look exactly like the records you need to write to (and read from) the random file.

Working with Random Access

In the second topic section, you learned about statements that you can use with sequential files. The Open and Close statements work the same for sequential and random-access files. The only difference between the two is in the access mode.

If you don't tell Visual Basic what mode to use to open a file, VB assumes For Random and fills in the mode for you. Suppose that you type the following:

Open "Random.Txt" As #1

Visual Basic changes the line to the following:

Open "Random.Txt" For Random As #1

The following statement opens a file for random access:

Open "Random.Txt" For Random As #1

You can open a file as a random-access file and then use it for sequential access. You sacrifice the benefits of a random-access file during the processing, but you may want to do this sometimes-especially if you've entered the records in a predefined order and you now want to print a report or display the file data in that exact order.

Consider an example of the difference between sequential and random access. Suppose that you create a file that contains 10 lines of inventory totals. To read the sixth line (record) of the file in sequential mode, you have to read the first five items to get to the sixth, and then have to read the last four items. If you access the file in random mode, you can go straight to record six, read the data, and close the file.

The same holds true for writing to a file. If you have the same 10-line file and you want to change the eighth record with sequential access, you have to read all 10 records in the file, change the eighth record, and write all 10 records back to the file. In random mode, you can just write the changes to the eighth record.

When a file contains only 10 records, you don't benefit much from a random file, but when the file contains 10,000 records, you save a lot of time and decrease system overhead when you use random access.

Using Get and Put

Two statements are used for random access files: Put # and Get #. These statements are similar to the Print # and Input # statements you used for sequential file access. The major difference between these two sets of statements is that Print # and Input # handle one piece of data at a time and work all the way through the file. There's no way for these statements to position to a specific record and update only that record.

The syntax for Put # and Get # is a little different from those of Print # and Input #:

Put [#]intChannel, [intRecNum,] Variable

Get [#]intChannel, [intRecNum,] Variable

As you can see, these statements use a record number. By specifying the record number you want to work with, you can update or read only certain data. Record numbers begin with 1. The variable you read or write can be of any data type-even an array or a user-defined variable (see the next section). The freedom to handle any type of variable as a single unit is one of the most powerful features of random-access files.

The examples at the end of this topic section include procedures that read and write particular records in a random-access file.

User-Defined Data Types

You already have learned about variables and arrays in this book. You'll now learn how to create your own data types consisting of other data types grouped together. These user-defined data types are sometimes called structures or records.

If you wanted to create a program that would allow you to maintain an address book for all your contacts, you could use individual variables for each field you needed. For example, you could use a string named strFName for the first name, a string named strLName for the last name, and so on. These separate variables would work; however, such programming would become cumbersome when you had a large number of contacts to manage. It would be much more easy to have one user-defined data type that contained all the same information and that you could handle as one entity just as you handle individual variables.

A user-defined data type is one that contains other existing data types grouped together to form a new data type. This grouping is referred to as a composite declaration.

A user-defined data type is composed of pre-existing data types (VB's built-in data types, other user-defined types, or both).

You use the Type statement to create your own data types. The format is as follows:

[Private | Public] Type TypeName

  VarName1[(ArraySize)) As ExistingType [* StringLength]

  VarName2[(ArraySize)] As ExistingType [* StringLength]

     :

     :

End Type

Notice that the name of the user-defined data type you want to create follows the Type keyword. This name can be any word that isn't a reserved word, keyword, or declared variable name. If you've already declared a variable named Client, for instance, you can't create a user-defined data type named Client.

You must declare all user-defined types at the module level; it's invalid to declare them inside procedures. You can declare a type in a form module, but this declaration must be Private, and the data type will be private to the form's module code only.

Examine the following code:

' Module Page of the Project

Type UserType

  strFName As String

  strLName As String

End Type

Public Names As UserType

This code creates a user-defined data type named UserType. It contains two strings, strFName and strLName. It also creates a variable named Names of type UserType.

UserType isn't a variable, but a type you've defined. Names is the variable name and strFName and strLName are called members or fields within the variable. You've added a new data type to the Visual Basic language for the duration of the program's execution. In addition to Integer and Boolean, you now can declare variables of the data type UserType.

To access the individual fields that make up the data type, use the variable name, a period, and then the field name.

The following statements initialize and work with the variable just declared:

Names.strFName = "John"

Names.strLName = "Doe"

lblFName.Caption = "First Name: " & Names.strFName

lblLName.Caption = "Last Name: " & Names.strLName

You can limit the size of string variables used in a structure by adding the * StringSize option to the declaration after an As String field type. The fixed-length string sets the absolute length of the string to StringSize. This usually is required when you're going to be randomly reading and writing your structures to a file. A fixed string length is needed to ensure that each record written to the file is the same size so that you can safely access records randomly.

To change the previous example to make the string sizes constant, consider the following code:

' Module Page of the Project

Type UserType2

  strFName As String * 8

  strLName As String * 20

End Type

Public Names As UserType2

The fixed-length strings limit the string length to an inflexible maximum. Although the string data may not consume the entire string space you've reserved, Visual Basic pads the remaining length with spaces to ensure that any variables declared with UserType2 and written to a random-access file will consume the same record length-no matter what data the variable holds.

Example

The procedure in Listing 21.6 demonstrates the basics of working with random files.

Listing 21.6 Random.bas: Writing to Any Record Number You Want

Private Sub cmdCreate_Click()

  ' This procedure creates the file

  Dim intChan As Integer   ' Free channel

  Dim intCtr As Integer    ' Loop counter

  intChan = FreeFile

  Open "c:\Random.Txt" For Random As #intChan Len = 5

  ' Loop through numbers and write file

  For intCtr = 1 To 5

    Put # intChan, intCtr, intCtr  ' Record # same as data

  Next intCtr

  Close intChan

End Sub

Private Sub cmdChange_Click()

  ' This procedure changes 3rd record

  Dim intChan As Integer   ' Free channel

  intChan = FreeFile

  Open "c:\Random.Txt" For Random As #intChan Len = 5

  ' Write a new 3rd record

  Put #intChan, 3, 9   ' Record 3, value: 9

  Close # intChan

End Sub

Private Sub cmdDisplay_Click()

  ' This procedure displays the file

  Dim intChan As Integer   ' Free channel

  Dim intVal As Integer    ' Read value

  Dim intCtr As Integer    ' Loop counter

  intChan = FreeFile

  Open "c:\Random.Txt" For Random As #intChan Len = 5

  Debug.Print "File Random.Txt opened..."

  ' Loop through records and write file

  For intCtr = 1 To 5

    Get # intChAn, intCtr, intVal

    Debug.Print " Retrieved a " & intVal & " from Random.Txt"

  Next intCtr

  Close # intChan

  Debug.Print "File Random.Txt is now closed"

End Sub

Notice that the random-access Open statement uses the Len = option. The procedure uses Put # to create a random-access file with a record length of 5; the Len = option specifies the record length. The record length is very important; if you didn't know the record length, Put # and Get # wouldn't know how far into the file to search for a particular record. (The formula for finding a record is RecordNumber * RecordLength.)

This example assumes that the form has three buttons. One creates the file, another displays the file, and a third changes the file. You can easily create such an application and run it. Click the Create button, and then click the Display button. Your Immediate window should look like Figure 21.3.

FIG. 21.3

Here are the results after writing the values to Random.txt.

Click the Change button and then click the Display button again. Your results now should look like those shown in Figure 21.4.

FIG. 21.4

The third record is different now.

This record used to show a 3

The third record in the file now holds 9 instead of 3. The subroutine that made this change simply wrote the 9 to record number 3, using Put # to access the correct record.

Next Step

You've seen how to create your first user-defined data type, but what if you want to include a user-defined data type inside another user-defined data type? One of the fields needs to be a user-defined data type rather than be one of the built-in VB data types. Just be sure to declare the user-defined data type you want included before you declare the user-defined data type you want to include it in.

Here's an example of one user-defined data type used as a field inside another:

' Entered into the Code module

Type Address

  strStreet As String

  strCity As String

  strZip As String

End Type

Type UserType3

  strFName As String * 10

  strLName As String * 25

  typAddr As Address  ' Another data type

End Type

Public Names As UserType3  ' Declare a variable

The following code initializes these fields and shows you how to get to the fields within fields:

Names.strFName = "Jonathan"

Names.strLName = "Doe"

Names.typAddr.strStreet = "AnyStreet"

Names.typAddr.strCity = "AnyTown"

Names.typAddr.strZip "12345-9876"

' Work with the data

lblFName.Caption = "First Name: " & Names.strFName

lblLName.Caption = "Last Name: " & Names.strLName

lblAddr.Caption = "Street: " & Names.strAddr.strStreet

lblCty.Caption = "City: " & Names.strAddr.strCity

lblZip.Caption = "Zip: " & Names.strAddr.strZip

Summary

In this lesson, you learned how to create and access files. Visual Basic supports three file modes, and you practiced working with the two most common-sequential and random. Sequential file processing is easier to code, but random file processing lets you access data that you need when and where you need it, without tediously reading and writing all other records in the file.

In Hour 22, you'll learn about OLE and see how to embed objects from other sources in your applications.

Hour 21 Quiz

  1. How many open files can you close with a single Close statement?
  2. What function returns the next unused file number?
  3. What happens if you open a file for sequential output access and the file already exists?
  4. What happens if you open a file for sequential append access and the file already exists?
  5. What type of file does the following statement open?
Open "TestFile.Dat" For Append As #1
  1. Why do random-access files need to know the record length of their data?
  2. Why should you specify the absolute length of strings within a user-defined data type if you're going to read and write those strings to a random-access file?
  3. What statement do you use to define your own data types?
  4. True or false: The following code declares a new user-defined variable named CustRec:
Type CustRec

  strFName As String * 10

  strLName As String * 15

  curBalance As Currency

  blnDiscount As Boolean

End Type
  1. True or false: You can't embed one user-defined data type within another user-defined data type.

Hour 21 Homework Exercises

  1. Write a program that creates a sequential file that holds the following information: name, age, and favorite color. Fill this file with five units of information (each unit should contain one name, one age, and one color). Use three For...Next loops to write this information to the file. Hint: You need to initialize three arrays, one for each kind of value you're writing.
  2. Write a program that creates a random-access file to store 20 numbers. Use an input box to query users for two things: the number of the record that should be updated next and the new value for that record. Then modify the record.
  3. Write a program that creates a random-access file that stores 100 names and addresses stored as the user-defined data type UserType3 presented at the end of this lesson's final topic section. Display a form for users with Save and Done command buttons. Put text boxes on the form to represent each piece of the record data. When users click Save, check the text boxes to see whether they contain data; if so, write the record to the random-access file. When users click Done, print the records backward (use Get #) in the Immediate window.

© 1997, QUE Corporation, an imprint of Macmillan Publishing USA, a Simon and Schuster Company.