## Visual Basic in 12 Easy Lessons vel18.htm

- What You'll Learn
- Disk File Background
- Opening Files
- Clean Up with Close
- Writing to Files With Write
- Inputting from Files with Input#
- Line Input# Really Makes it Easy
- Homework
  - General Knowledge
  - What's the Output?
  - Find the Bug
  - Write Code That...
  - Extra Credit

#
Lesson 9, Unit 18

##
Simple File I/O

###
What You'll Learn

- Creating the disk file background
- Opening files
- Cleaning up with Close
- Writing to files with Write
- Inputting from files with Input#
- Making it really easy with Line Input#

> > Definition: I/O means input and output.

This lesson explains how you can use Visual Basic code to manage disk file I/O. If you've collected data from the user and stored that data in variables and arrays, you can save the data to the disk for later retrieval. Also, you can access disk files from within Visual Basic for product inventory codes, amounts, customer balances, and whatever else your program needs from the long-term data file storage.

As you master Visual Basic and upgrade to other Visual Basic products, you'll add additional controls to your Toolbox window. There are several database access controls that read and write the data you've put in databases using products such as Microsoft Access and Paradox. Even though these controls provide more power and ease than you can get by programming alone, you'll still need the fundamentals of disk access. This unit explains a little on the background of disk access and teaches some of the most important disk commands and functions that you need to work with data files.

###
Disk File Background

Concept: A file is a collection of related data as well as programs that you buy and write, and documents from your word processor. Generally, you'll use Visual Basic to access data and text files stored on the disk.

There are all kinds of files on your computer's disks. Every file is stored under a unique filename to its directory and disk drive. Therefore, there can't be two or more files with the same filename unless the files reside in different directories or on different disks.

> > Definition: A data file holds data on the disk.

This unit is concerned with data files. Data files can take on all kinds of formats. Generally, newcomers to Visual Basic should stick with data files that are textual in nature. Text files are readable by virtually any kind of program, and virtually any program can produce text files. Sometimes, text files are called ASCII files because text files consist of strings of ASCII characters.

Before Visual Basic can access a file, you or the user will have to direct Visual Basic to the exact location on the exact disk where the file is stored. If your user is selecting a file, you'll want to use the file selection frame described in the previous unit to give the user the ability to change drives, directories, and filenames easily. When your program accesses a file that the user doesn't know about, your program will have to supply the drive, directory, and filename.

> > Note: The project at the end of this lesson contains an application that combines the file dialog frame that you mastered in the previous unit with the file I/O commands and functions described here to build a complete file access and display program.

Review: This unit teaches you how to access text data files stored on the disk. You'll need to supply Visual Basic with the filename, directory, and disk drive of any file with which Visual Basic works.

###
Opening Files

Concept: The Open statement opens files. Before Visual Basic can access a data file, Visual Basic has to open the file first. Think of the Open statement as doing for Visual Basic what an open file drawer does for you when you want to retrieve a file from a filing cabinet. The Open statement locates the file and makes the file available to Visual Basic.

The Open statement performs various tasks such as locating a file, making sure that the file exists if needed, and creating some directory entries that manage the file while the file is open. A Visual Basic program always has to open a file, using Open, before the program can read or write data to the file.

Here is the format of Open:

    Open FileNameStr [For mode] As [#]FileNumber

The FileNameStr must be a string value or variable that holds a filename. The filename must reside on the default drive or directory unless you specify the full path to the file. Generally, you won't have easy access to the user's current Windows default drive and directory, so you'll almost always specify the full drive and pathname inside the FileNameStr portion of the Open statement.

The mode must be a named value from Table 18.1. There are additional mode values, but this book won't cover the more advanced or the esoteric mode values. The mode tells Visual Basic exactly what your program expects to do with the file once Visual Basic opens the file.

Table 18.1. Possible mode values for the Open statement.

Mode | Description
Append | Tells Visual Basic that your program needs to write to the end of the file if the file already exists. If the file doesn't exist, Visual Basic creates the file so that your program can write data to the file.
Input | Tells Visual Basic that your program needs to read from the file. If the file doesn't exist, Visual Basic issues an error message. As long as you use a file selection frame properly, Visual Basic will never issue an error, because the file selection frame forces the user to select a file or cancel the selection operation.
Output | Tells Visual Basic that your program needs to write to the file. If the file doesn't exist, Visual Basic creates the file. If the file does exist, Visual Basic first erases the existing file and creates a new one under the same name, thereby replacing the original one.

The pound sign, #, is optional, although most Visual Basic programmers do specify the pound sign out of habit (some previous versions of the BASIC language required the pound sign). The FileNumber represents a number from 1 to 255 and associates the open file with that number. After you open a file successfully (assuming that there are no errors such as a disk drive door being left open), the rest of the program uses file I/O commands and functions to access the file. The file number stays with the file until you issue a Close command (see the next section) that releases the FileNumber and makes the number available to other files.

> > Note: As with all DOS and Windows file descriptions, you can specify the drive, directory, and filename using uppercase or lowercase characters.

You can open more than one file simultaneously within a single program. Each command that accesses one of the files directs its activity towards a specific file using that file's FileNumber.

The following Open statement creates and opens a data file on the disk drive and associates the file to the file number 1:

    Open "d:\data\myfile.dat" For Output As #1

If you knew that the file already existed and you needed to add to the file, you could use the Append mode to add to the file after this Open statement:

    Open "d:\data\myfile.dat" For Append As #1

One Visual Basic program can have more than one file open at the same time. There is an advanced FILES option in your computer's CONFIG.SYS file that determines the maximum number of files that can be open at one time. If the #1 FileNumber was in use by another file that you opened earlier in the application, you could assign the open file to a different number like this:

    Open "d:\data\myfile.dat" For Append As #5

Any currently unused FileNumber works; you can't associate more than one file at a time to the same FileNumber value.

The following Open would open the same file for input in a different program:

    Open "d:\data\myfile.dat" For Input As #2

Visual Basic supplies a helpful built-in function named FreeFile() that accepts no arguments. FreeFile() returns the next available file number value. For example, if you've used #1 and #2 for open files, the next value returned from FreeFile() will be 3. FreeFile() is most helpful when you write general-purpose subroutine and function procedures that need to open files, and the procedures may be called from more than one place in an application. At each calling location, there is a different number of files open at the time. The procedure can store the value of the next available file number like this:

    fNum = FreeFile()

and use the variable fNum in subsequent Open, I/O, and Close statements. No matter how many files are open, the procedure will always use the next file number in line to open its file.

Review: The Open command associates files using file numbers with which the rest of the program will access the file. The three mode values determine how Visual Basic uses the file. If you want to write to a file, you can't use the Input mode, and if you want to read from a file, you can't use Output or Append.

###
Clean Up with Close

Concept: The Close statement performs the opposite job from Open. Close closes the file by writing any final data to the file, releasing the file to other applications, and giving the file's number back to your application in case you want to use that number in a subsequent Open statement.

Eventually, every program that opens files should close those files. The Close statement closes files. These are the two formats of Close:

    Close [[#]FileNumber] [, ..., [#]FileNumber]

and

    Close

The first format closes one or more open files, specifying the files by their open file numbers. The pound sign is optional in front of any of the file numbers. The second form of Close closes all files that are currently open. Close closes any open file no matter what mode you used to open the file.

> > Tip: If you create a file by opening the file with the Output mode, and then close the file, you can reopen the same file in the same program in the Input mode to read the file.

The following statement closes the two open files that were opened and attached to the 1 and 3 file numbers:

    Close 1, 3

The following statement closes all files no matter how many are open:

    Close ' Closes ALL files

Review: Use the Close statement to close all open files before your program ends. Closing files provides extra safety, so close any and all open files when you're through accessing those files. If a power failure occurs during your program's execution, your closed files will be safely stored on the disk, but any files that are open at the time of the power failure could lose data.

###
Writing to Files With Write

Concept: The Write# command is perhaps the easier command to use for writing data to a file. Write# writes data of any data type to a file. Using corresponding input statements that you'll learn in the next section, you'll be able to read data that you sent to a file with the Write# command.

The Write# statement enables you to write data of any format to any disk file opened in the Output or Append mode. Write# writes strings, numbers, constants, variables, in any and all combinations to a disk file.

Here is the format of Write#:

    Write #FileNumber [, ExpressionList]

The FileNumber must be a file number associated to a file opened with Output. If you don't specify variables or values to write, Write# writes a carriage return and line feed character (an ASCII 13 followed by an ASCII 10) to the file, putting a blank line in the file. If you specify more than one value in the ExpressionList, Visual Basic writes that data to the file using the following considerations:

- Write# separates multiple items on the same line by adding commas between values
- Write# always adds a carriage return and line feed character to the end of each line written.
- Write# adds quotation marks around all strings in the file. The quotation marks make for easy reading of the strings later.
- Write# write date and time values using the following format:
  #yyyy-mm-dd hh:mm:ss#
- Write# writes the value of #NULL# to the file if the data is null (a VarType of 1).
- Write# writes nothing when the data value is empty (a VarType of 0), but does separate even empty values with commas if you write more than one value on a single line.

The code in Listing 18.1 writes a famous first century poem to a disk file named ODE.TXT. A command button named cmdWrite triggers the code's execution with its Click event when the user clicks the command button. The file appears on your C: drive's root directory.

Listing 18.1. Writing four string values to a file named ODE.TXT.

    1: Sub cmdWrite_Click ()

    2: ' Creates a text file and

    3: ' writes a poem to the file

    4: Open "c:\ode.txt" For Output As #1

    5:

    6: ' Write the poem

    7: Write #1, "Visual Basic, Visual Basic,"

    8: Write #1, "oh
    how I long to see..."

    9: Write #1, "A working application that"

    10: Write #1, "means so much to me."

    11:

    12: ' Always close any open file

    13: ' when done with the file

    14: Close #1

    15: End Sub

When Visual Basic closes the file in line 14, there will be a file in the user's root directory with the following contents:

    "Visual Basic, Visual Basic,"

    "oh how I long to see..."

    "A working application
    that"

    "means so much to me."

Typically, quotation marks never appear when you assign or display string values. The quotation marks are usually for the programmer to indicate the start and end of string values used in a program. The only exception to the appearance of quotation marks is that Write# always adds the quotation marks around all string data, whether the data is variable or constant, that Write# outputs to a file.

> > Definition: Append means to add to the end of something.

If you open a file using the Append mode, the Write# statement will add to the end of the file. The program in Listing 18.2 writes a blank line and a second stanza to the poem stored in the ODE.TXT file.

> > Warning: Remember that if you write to a file that already exists using the Output mode value, Visual Basic will erase the original contents and replace the file with the subsequent writing.

Listing 18.2. Code that adds to the end of a data file using the Write# statement.

    1: Sub cmdAddIt_Click ()

    2: ' Adds to a text file already created

    3: ' by writing a second verse to the file

    4: Open "c:\ode.txt"
    For Append As #1

    5:

    6: ' Add to the poem

    7: Write #1, ' Writes one blank line

    8: Write #1, "Visual Basic, to you I sing"

    9: Write #1, "the songs a programmer knows..."

    10: Write #1, "Listen carefully when I choose Run,"

    11: Write #1, "or we'll surely come to blows."

    12:

    13: Close #1

    14:

    15: End Sub

I'll give you a chance to get a handkerchief before looking at the newly expanded poem. Here is the result of the Append mode value if you were to display the contents of the ODE.TXT file after running this event procedure:

    "Visual Basic, Visual Basic,"

    "oh how I long to see..."

    "A working application that"

    "means so
    much to me."

    "Visual Basic, to you I sing"

    "the songs a programmer knows..."

    "Listen carefully when I choose Run,"

    "or we'll surely come to blows."

> > Tip: You may write data to files from variables as well as from controls on the form. Wherever you've got data that needs to be written, Visual Basic's Write# command will write that data to a disk file that you've opened.

Stop and Type: Listing 18.3 contains a subroutine procedure that accepts four arrays of four different data types and writes that array data to a disk file named VALUES.DAT. Notice how a simple For loop can be used to write a large amount of data to a data file. The fifth argument sent to the subroutine is assumed to contain the total number of elements defined for the arrays.

Review: The Write# statement provides one of the easiest file output commands inside the Visual Basic language. Write# separates multiple output values with commas and encloses all string data inside quotation marks.

Listing 18.3. Code that writes arrays using the Write# statement.

    1: Sub WriteData (CNames() As String, CBalc() As Currency, CDate() As Variant, CRegion() As
    Integer)

    2: ' Writes array data to a file

    3: Dim ctr As Integer ' For loop control

    4: ' Assumes that each array has the

    5: ' same number of elements defined

    6: Dim MaxSub As Integer

    7: MaxSub = UBound(CNames) ' The maximum subscript

    8:

    9: ' Write
    MaxSub lines to the file

    10: ' with four values on each line

    11: Open "c:\mktg.dat" For Output As #1

    12: For ctr = 1 To MaxSub

    13: Write #1, CNames(ctr), CBalc(ctr), CDate(ctr), CRegion(ctr)

    14: Next ctr

    15: Close #1

    16:

    17: End
    Sub

Output: Here are six sample lines from the MKTG.DAT file that the program in Listing 18.3 might write:

    "Adams, H", 123.41, #1997-11-18 11:34:21#,
    6

    "Enyart, B", 602.99, #21:40:01#, 4

    "Powers, W", 12.17, #1996-02-09#, 7

    "O'Rourke, P", 8.74, #1998-05-24 14:53:10#, 0

    "Grady, Q", 154.75, #1997-10-30 17:23:59#, 6

    "McConnell, I", 9502.32, #1996-07-12
    08:00:03#, 9

Review: Line 1 defines the subroutine procedure and accepts the four passed arrays. Each array is assumed to have the same number of defined subscripts. Although not all arrays passed to a procedure would necessarily have the same number of subscripts defined, these happen to do so. Line 6 and 7 defines and initializes a value that holds the maximum number of subscripts, so the subsequent For loop can write all of the array values to the file names MKTG.DAT.

The For loop in lines 12 to 14 step through the array elements, writing a line of four array values with each iteration. Visual Basic encloses the string array data with quotation marks and encloses the variant date and time data with pound signs.

The pound signs around the date and time variant values help Visual Basic when you subsequently read the data values back into variant variables. As you can see, the date may have a missing time or the time may have a missing date. Write# still writes as much of the date and time as is available within that variant value.

The Close statement on line 15 closes the file and releases the file number back to the program.

###
Inputting from Files with Input#

Concept: The Input# statement reads data from files and stores the file data in your program's variables and controls. Input# is the mirror-image statement to the Write# statement. Use Input# to read any data that you send to a file with Write#.

The Input# statement reads data into a list of variables or controls. Here is the format of Input#:

    Input #FileNumber [, ExpressionList]

Again, the bottom line to using Input# is that Input# is the mirror image of the Write# statement that produced the file data. When you write a program that must use data from a data file, locate the program's Write# statement that originally created the data file, and use that same format for the Input# statement.

> > Tip: Be sure to open all files that you'll read from using the Input file mode value, or Visual Basic will display an error message.

Listing 18.4 reads and displays in a scrolling list box the poem stored in the ODE.TXT file that was created in earlier listings.

Listing 18.4. Code that reads a poem using the Input# statement.

    1: Sub cmdList_Click ()

    2: ' Reads a poem from a text file and

    3: ' adds the poem, one line at a time,

    4: ' to the list box

    5: Dim ctr As Integer ' For loop control

    6: Dim PoemLine As String ' Holds each poem line

    7: Open "c:\ode.txt" For Input As #1

    8:

    9: '
    Read the poem

    10: For ctr = 1 To 9

    11: Input #1, PoemLine

    12: lstPoem.AddItem PoemLine

    13: Next ctr

    14:

    15: ' Always close any open file

    16: ' when done with the file

    17: Close #1

    18:

    19: End Sub

Figure 18.1 shows the list box that would appear as a result of Listing 18.4's execution.

Figure 18.1. The contents of a file shown in a list box.

> > Definition: A record is a row in a file.

When reading data from a file, you can very easily cause an error by attempting to read more data than the file holds. Listing 18.4 assumed that there were only nine records in the poem file to read, and that happened to be the case. For data files that hold data such as customer balances and employee pay values, however, the number of records varies because you'll add and remove records as transactions take place.

The Eof() function is Visual Basic's built-in end of file function that senses when an input reaches the end of file. Here is the format of the Eof() function:

    Eof(FileNumber)

Eof() returns True if the most recent reading of the input file just reached the end of the file and returns False if the input file still has data left to be read. Most data input programs loop until the Eof() condition is true. Perhaps the best way to use Eof() is with a Do Until-Loop that follows this general format:

    Input #1, VariableList ' Read the first record

    Do Until (Eof(FileNumer) = True)

     ' Process the record just read

     Input #1, VariableList ' Get more
    data

    Loop

If there are none, one, or four hundred records in the file, this format of Do Until will keep reading, but will stop as soon as the end of file is reached. Many programmers often increment an integer counter variable inside the loop to count the number of records read. The counter is useful if you're reading the file's data into arrays.

> > Note: If you read file data into arrays, be sure to dimension more than enough array elements to hold the maximum number of records expected.

Stop and Type: Listing 18.5 reads the file written earlier using a series of Write# statements back in Listing 18.3. The body of the code isn't shown. The code is supposed to output the file's contents to a printed paper report. You won't master the reporting commands until Lesson 11, so comments were used in place of the actual reporting commands.

Review: As long as you output to files using Write#, you'll easily read that same data back again using Input#. Input# is the mirror-image command to Write#. The combination of Write# and Input# makes file I/O simpler than possible in most programming languages.

Listing 18.5. Reading and reporting file data using Input#.

    1: Sub ReadData ()

    2: ' Reads array data from a file and reports the data

    3: ' Assume that 200 values were read

    4: Static CNames(200) As String, CBalc(200) As Currency

    5: Static CDate(200) As Variant, CRegion(200) As Integer

    6: Dim NumVals As Integer ' Count of records

    7: Dim ctr As Integer ' For loop control

    8:

    9: NumVals = 1 ' Start the count

    10: ' Reads the file records assuming

    11: ' four values on each line

    12: Open "c:\mktg.dat" For Input As #1

    13: Input #1, CNames(NumVals), CBalc(NumVals),
    CDate(NumVals), CRegion(NumVals)

    14: Do Until (Eof(1) = True)

    15: NumVals = NumVals + 1 ' Increment counter

    16: Input #1, CNames(NumVals), CBalc(NumVals), CDate(NumVals), CRegion(NumVals)

    17: Loop

    18:

    19: ' When loop ends, NumVals holds one too many

    20: NumVals = NumVals - 1

    21:

    22: ' The following loop is for reporting the data

    23: For ctr = 1 To NumVals

    24: ' Code goes here that outputs the array

    25: ' data to the printer

    26: '

    27: Next ctr

    28: Close #1

    29:

    30: End Sub

Analysis: Lines 4 and 5 define four arrays that will hold the file's data. The arrays are defined to hold, at most, 200 values. There is no error checking to be sure that the reading doesn't read more than 200 records, but an exercise at the end of the chapter gives you the chance to add this array-checking code.

Line 9 initializes NumVals to hold the count of file records. The count begins at 1 because the first array subscript that will hold incoming data is 1. (As with all programs in this book, this code ignores the 0 subscript that all arrays contain unless you specify Option Base 1.)

Line 12 opens the file for input and associates the file to the file number 1. The first input occurs on line 13. The input attempts to read the first record in the file that contains four values. Line 14's relational test for an end of file condition will immediately be true if the file is empty. Otherwise, the body of the loop executes. Line 15 increments the record count once more owing to line 16's input into the next set of array elements. The loop continues until the end of file is reached and line 14's relational test becomes false.

Line 20 must decrement the NumVals variable by 1 because the last attempt at reading the file will always produce an end-of-file condition. Therefore, the final Input# was unsuccessful and the record count can't contain that unsuccessful read.

After you read all the data into the arrays, you can work with the array data just as you normally work with array data. You can calculate statistics based on the data, display the array using list boxes and combo boxes, or print the data to paper.

###
Line Input# Really Makes it Easy

Concept: The Line Input# command reads data from open data files. Unlike Input#, Line Input# reads each line of data in the file into a string variable. You don't have to specify separate variable names after a Line Input# because Line Input# requires a single string value. Line Input# reads data from any file whose lines end with a carriage return and line feed sequence. (Most files do.)

The Line Input# command is simple to use for reading entire records into a single variable. Whereas Input# reads each records values individually, Line Input# reads an entire record—data, commas, quotation marks, and everything else—into a string or variant variable or control.

Here is the format of Line Input#:

    Line Input #FileNumber, VariableName

No matter how many record values appear in the file associated with file number 3, the following Line Input# statement reads an image of the record into the string variable named aRecord:

    Line Input #3, aRecord

Review: The Line Input# command reads records from data files into string or variant variables. The Input# command reads each record's individual data values into a single variable (or control). The Line Input# command reads entire records into string or variant variables. The project at the end of this lesson uses Line Input# to read an entire file using a single string variable.

###
Homework

####
General Knowledge

1. What is a file?
2. What are the purposes of files?
3. True or false: Your computer system can contain more than one file with the same filename.
4. What statement prepares a file for use by a program?
5. What are the three modes possible in the Open statement?
6. What is the purpose of the file number?
7. If a file doesn't exist and you open the file for output, what does Visual Basic do?
8. If a file does exist and you open the file for output, what does Visual Basic do?
9. If a file doesn't exist and you open the file for appending, what does Visual Basic do?
10. If a file does exist and you open the file for appending, what does Visual Basic do?
11. If a file doesn't exist and you open the file for input, what does Visual Basic do?
12. What is the range for the Open statement's file number?
13. True or false: When opening a file, you must specify the filename using lowercase letters.
14. What CONFIG.SYS command limits the number of files that you can have open at one time?
15. Which function locates the next available file number?
16. Which statement cleans up a file after you're done with the file?
17. Why is the Close command recommended?
18. Which open files does the following statement close?
19. Close
20. Which statement writes data to a file?
21. What character does Write# use to separate values in the output?
22. What character does Write# place around date and time values?
23. What character does Write# place around string values?
24. Which statement is the mirror-image input statement for Write#?
25. What is a record?
26. Which function tests for the end of file?
27. Which statement reads an entire record into a string or variant variable?

####
What's the Output?

1. What does the file record look like after the following Write# completes?
   Write #1, "Peach", 34.54, 1, "98"

####
Find the Bug

1. Rusty the programmer wants to read an entire record into a string variable named MyRecord, but his attempt shown as follows doesn't work. Help Rusty fix the problem.
   Input #1, MyRecord

####
Write Code That...

1. Write a Close command that closes an input file associated with file number 3 and an output file associated with file number 19.
2. Write the Open command needed to open a file named NAMES.DAT for append mode. Associate the file to file number 7.
3. Change Listing 18.5 to display a message box and exit the file-reading loop if the input data file contains more than 200 records. (The arrays holding the incoming data can't hold more than 200 values.)

####
Extra Credit

Write a subroutine procedure that writes four records of your four best friends' first names, ages, weights, and IQs (remember, these are your friends, so be gentle). Write a second procedure that reads that data into string variables one record at a time.