File Access with Visual Basic® for Applications

Table of Contents

  • Using Sequential Access
      Opening Files for Sequential Access
      Reading Files Opened for Sequential Access
      Writing to Files Opened for Sequential Access

  • Using Random Access
      Reading Files Opened for Random Access
      Writing to Files Opened for Random Access

  • Using Binary Access
      Opening Files For Binary Access
      Writing to Files Opened for Binary Access
      Reading Files Opened For Binary Access

Overview

This document describes how to process files with the file input/output (I/O) functions that Visual Basic for Applications provides. By processing files your program can create, manipulate, and store large amounts of data, access several sets of data at once, and share data with other programs.

In Visual Basic for Applications, there are three types of file access. These types are listed in the following table.

 
Type Access Note
Sequential Used with simple text files.
Random Access Used for files that are composed of a series of records of identical length.
Binary Used for files with no general format. You must know exactly how the data is written to the file in order to retrieve it.

By itself, a file consists of nothing more than a series of related bytes located on a disk. When your program accesses a file it must make assumptions about what the bytes are supposed to represent (integers, strings, or other data types). Visual Basic for Applications provides functions and statements that allow you to process the file based on these assumptions. The table below lists some of the file access functions and statements that Visual Basic for Applications provides for different types of file access:
File Access Functions Function's Action Sequential Access Random Access Binary Access
Close Closes the file X X X
EOF Tests for end of file X X X
FreeFile Returns the next file number available for use by the Open statement. X X X
Get Reads data from a file at a specific record number   X X
Input$ Returns all characters (bytes) from an open file X   X
Input # Reads a line of text into a list of variables X    
Line Input # Reads an entire line of text into a single variable X    
Loc Returns the current read/write position within an open file. X X X
LOF Returns the size, in bytes, of a file opened using the Open statement X X X
Open Opens a file with a specified access type X X X
Put Writes data to a file at a specific record number   X X
Seek Returns the current read/write position within a file opened using the Open statement X X X
Write # Writes data to a file opened for sequential access X    

Table 1: Visual Basic for Applications File Access Functions and Statements

This document contains example macros to demonstrate how to access files with these Visual Basic for Applications functions. The macro examples in this document may be used with Microsoft Excel versions 5.0, 7.0, and Microsoft Excel 97. You can download a workbook that contains these macro examples and the text files used in these examples. To use the sample macros copy the workbook and the text files to a directory named C:\FILEIO.


Return to Top of Page

Using Sequential Access

Sequential access is used to work with files that are just plain text files. This is the file type that you will more than likely encounter the most in Visual Basic for Applications. As an example, if you wanted to read each line in an Autoexec.bat or Win.ini file you could use sequential access.

With sequential access, each character in the file is assumed to represent either a text character or a text formatting sequence such as a tab or a new line character. Files such as CSV (comma separated), TXT (tab delimited) and PRN (space formatted) are all examples of files you would access sequentially.

Advantages of Sequential Access:

  • Files can be easily created or manipulated by text editors.
  • Most applications can read/write files created with sequential access.
  • It is easier to process in Visual Basic for Applications.

Disadvantages of Sequential Access:

  • It is not well suited for storing large amounts of data because all values are stored as a character string.
  • Usually requires more storage space than the other access types.
  • You cannot read and write to a file that is opened for sequential access. You can only do one or the other at any given time.

Opening Files for Sequential Access

When you open a file for sequential access, you open it to perform one of the operations in the following table:

 
Operation Description
Input Input characters to the file.
Output Output characters to the file.
Append Append characters to the end of the file.
To open a file for any one of these operations use the Open statement:

    Open filename For [Input | Output | Append] As filenumber Len=buffersize

When you use sequential access to open a file for Input, the file must already exist; otherwise Visual Basic for Applications generates a trappable error. When you try to open a nonexistent file for Output or for Append, the Open statement will actually create the file first and then open the empty file. Each time you open a file you must Close it before reopening the file for another type of operation.


Return to Top of Page

Reading Files Opened for Sequential Access

To retrieve the contents of a text file, you first open the file for input, then use Line Input # or Input # to retrieve the contents of the file. Use Line Input # when you need to read a file one line at a time. With delimited files (such as tab or comma separated values), use Input # to read each line of the file into a list of variables.

Reading a File Line-by-Line

Use Line Input # with a file opened for sequential access if the data is stored in the file one line at a time. The Line Input # statement reads from a file one character at a time until it encounters a carriage return or carriage return-linefeed sequence. Carriage returns and carriage return-linefeed sequences are skipped rather than appended to the character string. Figure 1 is a text file you can use with the Line Input # statement to read from the file one line at a time.
    This is the first line of the file
    		This is the second line of the file
    		This is the third line of the file
    		This is the fourth line of the file
    		This is the last line of the file
Figure 1: Sample Text File Textfile.txt

Microsoft provides examples of Visual Basic for Applications procedures for illustration only, without warranty either expressed or implied, including, but not limited to the implied warranties of merchantability and/or fitness for a particular purpose. The Visual Basic procedures in this article are provided 'as is' and Microsoft does not guarantee that they can be used in all situations. While Microsoft Support Professionals can help explain the functionality of a particular macro, they will not modify these examples to provide added functionality, nor will they help you construct macros to meet your specific needs. If you have limited programming experience, you may want to consult one of the Microsoft Solution Providers. Solution Providers offer a wide range of fee-based services, including creating custom macros. For more information about Microsoft Solution Providers, call Microsoft Customer Information Service at (800) 426-9400.

The following sample macro uses the Line Input # statement to read data from the sample text file in Figure 1:

Sub ReadStraightTextFile()
Dim LineofText As String
'Open the file for Input
    Open "C:\FILEIO\TEXTFILE.TXT" For Input As #1
    'Read each line of the text file into a single string   
    'variable
    Do While Not EOF(1)
        Line Input #1, LineofText
        Debug.Print LineofText
    Loop
        'Close the file
    Close #1
End Sub

Reading a Delimited Text File

Standard string or numeric data is assigned to variables as they appear in the text file. Delimiting commas or blank lines within the file are returned as Empty. Double quotation marks that surround each field in the input data are ignored and fields surround with "#"'s are interpreted as dates. When using Input #, data items in a file must appear in the same order as the variables in the variable list and they must be matched with variables of the same data type. If the data doesn't match the variable type you may encounter run-time errors.

"Smith", "John", 22, "123 Main St.", "New York", "NY", 32432
"Doe", "Jane", 33, "324 Elm Ln.", "San Diego", "CA", 23542
"Adams", "Bill", 45, "4523 Oak Cir.", "Miami", "FL", 52343
"Jones", "Tom", 23, "235 Maple Dr.", "Houston", "TX", 23453

Figure 2: Sample Delimited Text File Delimit.txt

This sample code below uses the Input # statement to read data from the sample text file in Figure 2 into variables.

Sub ReadDelimitedTextFile()
Dim LName As String, FName As String, Addr As String, City As String
Dim state As String
Dim age As Integer
'Open the file for Input
    Open "C:\FILEIO\DELIMIT.TXT" For Input As #1
'Read each line of the text file into the list of variables
    'until the end of the file is reached
    Do While Not (EOF(1))
        Input #1, LName, FName, age, Addr, City, state, zip
        Debug.Print LName, FName, age, Addr, City, state, zip
    Loop
'Close the file
    Close 1
End Sub

Return to Top of Page

Writing to Files Opened for Sequential Access

To store the contents of variables in a sequential text file, open it for sequential access and then use either the Print # or Write # statement to write the data to the file.

The Write # statement writes comma-delimited format data to the text file and uses the following syntax:

 

    Write#filenumber[,outputlist]

When you write to the file using Write #, string fields are surrounded with double quotation marks and date fields are surrounded with #'s. In this respect, Write # is a companion to Input #. The following macro demonstrates how you can write to a delimited text file:

Sub WriteFile()
Dim LName As String
Dim BDay As Date
Dim age As Integer
'Create a new text file called TEST.TXT
    Open "C:\FileIO\TEST.TXT" For Output As #1
'Create and then write the first "record"
    LName = "Doe"
    BDay = #1/1/95#
    age = 1
    Write #1, LName, BDay, age
'Create and then write the second "record"
    LName = "Smith"
    BDay = #4/29/56#
    age = 39
    Write #1, LName, BDay, age
'Create and then write the third "record"
    LName = "Jones"
    BDay = #5/1/80#
    age = 15
    Write #1, LName, BDay, age
'Close the file
    Close #1
End Sub

When the macro "WriteFile" is done, you will have a comma-delimited text file named Test.txt that looks like the following:

"Doe",#1995-01-01#, 1

"Smith",#1956-04-29#,39

"Jones",#1980-05-01#,15

Unlike Write #, the Print # statement writes display-formatted data (or space-formatted data) to a sequential file and uses the following syntax:

 

    Print # filenumber,[outputlist]

In the list of output variables for Print #, you can specify the number of spaces to separate fields. For more information, see the online help topic for the Print # statement.

If you were to change "Write #" to "Print #" in the macro WriteFile the file Test.txt would look like the following:

Doe 1/1/95 1

Smith 4/29/56 39

Jones 5/2/80 15

Modifying Data in a File Opened for Sequential Access

Note that when you open a file for Output, and the file already exists, you are essentially replacing the contents of the file when you write to it. The new data that is written is not appended to the file. In order to append data to the end of a file you must open the file for Append. All data that is written to a file opened for Append is added to the very end of the file. There is no way to modify the records in a file opened for sequential access, but there is a process to workaround this:

1. Open the file for Input and read all of the data into variables.

2. Close the file.

3. Make the necessary modifications to the data contained in the variables.

4. Open the file for Output and write all of the modified data to the file.

5. Close the file.

Because of the number of steps required to make modifications to a file opened for sequential access, it may not be the most efficient method for modifying data in a text file particularly if the text file is relatively large.


Return to Top of Page

Using Random Access

A file opened for random access is assumed to be composed of a series of records of equal length. Each record must correspond to a single data type (an integer, a string, or a user-defined type). The length of each record depends on its data type. The table below demonstrates the size of each record for a few data types.

 

Record Data Type

Bytes Required by Each Record

Comment

Integer

2

An integer requires 2 bytes.

String*1 (A)

1

Each character in a string needs 1 byte.

String*20

20

Each character in a string needs 1 byte.

 

Type MyRecord
     LastName as String*20
     FirstName as String*20
     Age as Integer
     Married as Boolean
End Type

44

LastName requires 20 bytes, FirstName requires 20 bytes, Age requires 2 bytes, and Married requires 2 bytes, thus, one record requires 44 bytes ( 20+20+2+2=44).

Table 2: Bytes Required for Records

(A) When dimensioning string variables to use as a record type for random access you must specify a length for the string since each record should be of equal length. In other words, use only fixed length strings for storing the records of a file opened for random access.

Advantages of Random Access:

  • Compared to Sequential access, you may save significant disk space required by the file.
  • Files can be opened for both read and write at the same time.

Disadvantage of Random Access:

  • You can waste space if fields in the records are left blank or if most of the record strings are significantly shorter than the length dimensioned for the string.

Return to Top of Page

Reading Files Opened for Random Access

As previously described, the bytes in random-access files form identical records where each record contains one or more fields. A record with one field corresponds to any standard type such as integer or fixed-length string. A record with more than one field corresponds to a user-defined type. For example, Figure 3 shows how one file can form 22-byte records that consist of 12, 8, and 2 byte fields.

 

Figure 3: Sample Records in a File Named Random.xxx

In a file opened for random access all records must correspond to one type. All of the records in Figure 3 could correspond to the following user-defined type:

Type Person
   LName as String*12
   FName as String*8
      Age as Integer
End Type

Before opening a file for random access, you must create a user-defined type that corresponds to the records the file contains. Because records in a file opened for random access must have the same length, user-defined type string elements must have a fixed-length. If the string copied into the file record contains fewer characters than the fixed length of the string variable, the field is padded with trailing spaces; this can create wasted space in the file. If the string copied into the file record contains more characters than the fixed length of the string variable, the string will be truncated.

To open a file for random access use the following syntax for the Open statement:

    Open filename For Random As Filenumber Len=RecordLength

Len=RecordLength is used to specify the size of each record. If this value is not correct, access to the file will produce unexpected results. In your macro you can use the Len function to determine the size of the user-defined type or variable that represents a record in the file.

To read the data in a file opened for random access use the Get statement. The Get statement has the following syntax:

    Get #filenumber,[recnumber],varname

When you use a file opened for random access, recnumber is the record number at which reading begins and varname is the variable into which data is read. The first record in such a file is at position 1, the second record is at position 2, and so on. If you omit recnumber the next record is read.

You can use the following macro to create the file shown in Figure 3.

Type Person
   LName as String*12
   FName as String*8
      Age as Integer
End Type
Sub ReadRandom()
Dim P As Person 'Create a variable of user-defined type Person
'Open the file for random access and specify that the length
    'of each record is equal to the record length of P
    Open "C:\FileIO\RANDOM.XXX" For Random As #1 Len = Len(P)
'Read each record in the file and display it in the debug
    'window. The number of records in the file is determined by
    'the integer value of Total Bytes in File/Bytes in Each 
    'Record
    For i = 1 To Int(LOF(1) / Len(P))
        Get 1, i, P
        Debug.Print P.LName, P.FName, P.Age
    Next
'Close the file
    Close 1
End Sub

Return to Top of Page

Writing to Files Opened for Random Access

Put is the companion statement to Get. When writing records to files opened for random access use the Put statement. The Put statement has the following syntax:

    Put [#]filenumber,[recnumber],varname

Similar to Get, recnumber is the record number at which writing begins and varname is the variable data is written from. The first record in such a file is at position 1, the second record is at position 2, and so on. If you omit recnumber the next record is written.

To create a new file similar to Figure 3 use the following macro:

Sub WriteRandom()
Dim P As Person 'Create a variable of user-defined type Person
'Open the file for random access and specify that the length
    'of each record is equal to the record length of P
    Open "C:\FileIO\RANDOM.XXX" For Random As #1 Len = Len(P)
'Create and write the first record
    P.LName = "Doe"
    P.FName = "Jane"
    P.Age = 9
    Put 1, , P
'Create and write the second record
    P.LName = "Thompson"
    P.FName = "Richard"
    P.Age = 4
    Put 1, , P
'Continue to add additional records if needed...
'Close the file
    Close #1
End Sub

Editing Records in a File Opened for Random Access

Using both Get and Put statements you can edit a single record by specifying the record number. Use Get to read the record into a variable make the necessary changes, and then use Put to write the record back to the file. For example, to change Richard Thompson's age from 4 to 5 in the file Random.xxx (note that Richard Thompson is the second record), use the following macro:

Sub ChangeRecord()
Dim P As Person 'Create a variable of user-defined type Person
'Open the file for random access and specify that the length
    'of each record is equal to the record length of P
    Open "C:\FileIO\RANDOM.XXX" For Random As 1 Len = Len(P)
'Get the contents of the second record and place them in the
    'variable P
    Get 1, 2, P
'Change the Age field in P to 5
    P.Age = 5
'Write P back to the file at the second record
    Put 1, 2, P
'Close the file
    Close 1
End Sub

After you run the ChangeRecorrd macro, the file looks like Figure 4.

Figure 4: Records in Random.xxx After Running the ChangeRecord Macro

Appending Records Opened for Random Access

To append records to the end of a file, determine the record number of the new record and write it to the file. To determine the new record number, calculate the number of records in the file and then add one.

The AppendRecord macro appends a new record to Random.xxx:

Sub AppendRecord()
Dim P As Person 'Create a variable of user-defined type Person
'Open the file for random access and specify that the length
    'of each record is equal to the record length of P
    Open "C:\FileIO\RANDOM.XXX" For Random As 1 Len = Len(P)
'Write the new record to the end of the file
    'The new record number is determined by taking the Length of
    'the file divided by the size of the record plus one.
    P.LName = "Smith"
    P.FName = "Bill"
    P.Age = 30
    Put 1, Int(LOF(1) / Len(P)) + 1, P
'Close the file
    Close #1
End Sub

After you run the ChangeRecord macro, the file looks like Figure 5.

Figure 5: Records in Random.xxx After Running the Macro AppendRecord


Return to Top of Page

Using Binary Access

Binary access allows you to use files to store data however you want; there are no assumptions made about data type or requirements for standard record length. However, you must know precisely how the data is written to the file to retrieve it correctly.

For example, if you retrieve the data at file location 112 as an integer bytes, 112 and 113 are retrieved to make up an integer value. It does not matter that these two bytes may be part of 4 bytes previously stored as Long integer type; your program must keep track of the contents of the file and make sure that such actions are correct.

Advantages of Binary Access Files:

  • You can conserve disk space by building variable-length records.

  • You can read and write to a file opened for binary access as you can with random access.

Disadvantage of Binary Access Files:

  • You must know precisely how the data is written to the file to manipulate it successfully

To understand how and when to use binary access, consider the Person records that were used to demonstrate random access. This example used records and field of fixed length to store information. The Person record for random access was:

Type Person
   LName as String*12
   FName as String*8
   Age as Integer
End Type

With random access, every record required 22 bytes regardless of whether or not the data required that space. This waste may be avoided by using binary access since it does not require equal length records. For binary access you can change the Person data type to:

Type Person
   LName as String
   FName as String
   Age as Integer
End Type

Opening Files For Binary Access

To open a file for binary access use the following syntax for the Open statement:

 

    Open file For Binary As filenumber

Open for binary access differs from Open for random access in that a record length is not specified. In fact, if you do specify one it is ignored. Return to Top

Writing to Files Opened for Binary Access

Since records with binary access can be of variable length, it is necessary to store information about the size of each field and record so that it can read successfully. A good way to do this is to store an integer with each string to indicate the length of the string. Here's an example of such a file:

Type Person
   LName as String
   FName as String
   Age as Integer
End Type
Sub WriteOneRecord(PRecord as Person)
Dim StrSize as Integer
   'Write the LName field and indicate the length of LName
   'since it is a variable-length string
   StrSize = Len(PRecord.LName)
   Put 1,,StrSize
   Put 1,,PRecord.LName
   'Write the FName field and indicate the length of FName
   'since it is a variable-length string
   StrSize = Len(PRecord.FName)
   Put 1,,StrSize
   Put 1,,PRecord.FName
   'Write the Age field – this is type integer so it is not 
     'necessary to indicate a length
   Put 1,,PRecord.Age
End Sub
Sub WriteBinary()
Dim P as Person
   'Create a new file and open it for Binary access
   Open "C:\FileIO\BINARY.XXX" For Binary As 1
   'Create and write the first record
   P.LName = "Doe"
   P.FName = "Jane"
   P.Age = 9
   WriteOneRecord P
   'Create and write the second record
   P.LName = "Thompson"
   P.FName = "Richard"
   P.Age = 4
   WriteOneRecord P
   'Close the file
   Close 1
End Sub

When the WriteBinary macro is run, it creates a file called Binary.xxx that will have the structure shown in Figure 6. The two records in this example take up 34 bytes (as opposed to the 44 bytes required by the same data with random access).

Figure 6: Binary.xxx Created by the Macro WriteBinary

A trade-off in using variable-length field and binary access instead of fixed-length fields and random access is that the entire record could be written with a single function call using random-access. While binary access provides greater flexibility, it also requires more code to handle I/O operations. Return to Top

Reading Files Opened For Binary Access

The Get statement reads a number of bytes equal to the bytes required for the variable that is used. When you use Get with a variable-length string, the number of bytes read from the file equals the current length of the string. To temporarily set the length of a variable-length string you can use the String$ function to set the variable equal to a specific number of spaces.

This example reads a file like the one created with the WriteBinary macro:

Type Person
   LName as String
   FName as String
   Age as Integer
End Type
Sub ReadOneRecord(PRecord as Person)
Dim StrSize As Integer
   'Determine the size of the LName field and read it
   Get 1, , StrSize
   PRecord.LName = String(StrSize," ")
   Get 1, , PRecord.LName
   'Determine the size of the FName field and read it
   Get 1, , StrSize
   PRecord.FName = String(StrSize," ")
   Get 1, , PRecord.FName
   'Read the Age field
   Get 1, , PRecord.Age
End Sub
Sub ReadBinary()
Dim P as Person
   'Open the file for binary access
   Open "BINARY.TXT" For Binary As 1
   'Read each record in the file and display it in the debug 
     'window   
   Do Until Loc(1) >= LOF(1)
      ReadOneRecord P
      Debug.Print P.LName, P.FName, P.Age
   Loop
   'Close the file
   Close 1
End Sub

Return to Top of Page

 

Last Reviewed: Tuesday, February 13, 2001
© 2001 Microsoft Corporation. All rights reserved. Terms of Use.  Disability/accessibility  Privacy Policy