Sometimes, you may need to store and retrieve information but not need the power of a database (not to mention the extra coding, configuration, and support files that go along with it). In these cases, a text file may be just the thing you need. In this section, you will learn about a simple type of file: a free-form, sequential text file. Sequential means that the file is accessed one byte after the other in sequence, rather than jumping to a specific location. Free form means that the file has no predefined structure; its structure is entirely up to the programmer.
Sequential Text Files
Suppose that you have a form in which the user must choose salespersons from a list, as shown in Figure 21.3. Your mission is to load the names of each salesperson into a list box so that the user can select these names. You could just put a bunch of AddItem statements in the Form_Load event. However, doing so would be a poor solution because you have hard-coded information in the program. Any time the sales force changed, the program would have to be recompiled. A better solution is to use a text file with the salespersons' names in it. The program then reads the names from the text file and populates the list box.
The list box is populated with the contents of a text file.
To create the file itself, you can use a text editor such as Notepad, and place each salesperson's name on a separate line, as shown in Figure 21.4.
Data stored in sequential text files can be easily edited.
This process is simple, and the file can be edited by anyoneeven if that person doesn't have a database tool. For example, a secretary could maintain this file on a network server, and the application could copy the most recent version at startup. Of course, if you are using a database anyway, you might want to go ahead and place the names of the sales force in a table. However, a standard text file could still be used for importing into the table.
The concept of a shared network file also applies to databases and other documents, which may be useful if everyone on your network uses the same desktop application programs.
Reading from a Sequential Text File
Now that you know how easily you can create a sequential text file, you're ready to write some code to read information from the file. One easy way to process a sequential text file is to read it a line at a time. For the salesperson example described in the preceding section, the steps used for filling up the list box are very straightforward:
Open the file for input.
Read a line from the file, and store it in a variable.
Add the contents of the variable to the list box.
Repeat steps 2 and 3 for each line in the file.
Close the file.
The code for filling up the list box, which is discussed in the following sections, is shown in Listing 21.1.
Listing 21.1 Filling a List Box from a Text File
Sub FillListBox() Dim sTemp As String lstPeople.Clear Open "C:\DATA\PEOPLE.TXT" For Input As #1 While Not EOF(1) Line Input #1, sTemp LstPeople.AddItem sTemp Wend Close #1 End Sub
Now, examine the code a little more closely. First, before you read or write information, you must open the file with the Open statement. The Open statement associates the actual filename (PEOPLE.TXT in the example) with a file number. A file number is an integer value used to identify the file to other Visual Basic code:
Open "C:\DATA\PEOPLE.TXT" For Input As #1
In the preceding example, 1 is the file number. However, if you open and
close multiple files throughout your program, using this number might not
be a good idea. In that case, you should use the FreeFile function,
which returns the next available file number, as in the following example:
Dim nFile As Integer
nFile = FreeFile
Open "C:\MYFILE.TXT" for Input As #nFile
After you finish using a file, you should close it with the Close statement (refer to Listing 21.1). This way, you can free up the file number for use with other files.
In addition to providing the filename and number association, the Open statement tells Visual Basic how you intend to use the specified file. (Many different options are available with the Open statement, as discussed in the Help file.)
Before you open a file for input, use the Dir$ function to see whether it actually exists.
The keyword Input indicates that the file will be opened for Sequential Input, which means that you can only move forward through the file in sequence. The act of reading information from the file automatically moves an internal file pointer forward for the next read. The code in Listing 21.1 uses a Line Input statement in a While loop to read information. The first Line Input statement reads the first line, the second Line Input reads the second line, and so on. A line in a file is delimited by an end of line marker, which in Windows is the carriage return character followed by the line feed character. The syntax of the Line Input statement is
Line Input #filenumber,variablename
where filenumber is an open file number and variablename is a string or variant variable. If you try to read more lines of text than are in the file, an error occurs. Therefore, you should use the EOF (end-of-file) function to check whether you have reached the end of file before attempting to read again.
After you open the file, you can choose from several methods of reading information from it. In the example, each name is the only piece of information on each line, so no further processing on the string variable is necessary. However, sometimes you may want to read less than a whole line or store more than one piece of information on a single line. In these cases, you can use the Input # statement or the Input function.
The Input # statement is designed to read information stored in a delimited fashion. For example, the following line of a text file contains three distinct pieces of information: a string, a number, and a date. Commas, quotation marks, and the # symbol are used to delimit the information.
The following line of code correctly reads each item from the file into the appropriate variables:
Input #1, stringvar, intvar, datevar
Remember that the Input # statement looks for those delimiters, so make sure that your Input # statements match the format of the file.
Another method of reading information is the Input function. The Input function allows you to specify the number of characters to read from the file, as in the following example:
'Reads five Character from file number 1 s = Input(5,#1)
Now, compare how each of the methods just discussed would process the same line in a file:
'Assume our file has the following line repeated in it: "This is a test string." Dim s As String Line Input #1, s 's contains the entire string including quotes Input #1, s 's contains the string without quotes s = Input(5,#1) 's Contains the first 5 characters ("This)
Writing to a Sequential Text File
One good use of a sequential text file is a log file. For example, I have a scheduler application that runs programs and database updates. I rarely work at the machine on which the scheduler application is running, but I can connect over the network and view the log file to see whether the updates have completed.
You can create batch files, FTP scripts, and many other simple file formats on-the-fly by using sequential text files.
Listing 21.2 is a subroutine called LogPrint, which can be added to your program to log error messages. It writes the error message and date to a sequential text file.
Listing 21.2 Using a Sequential Output File to Build an Application Log
Sub LogPrint(sMessage As String) Dim nFile As Integer nFile = FreeFile Open App.Path & "\ErrorLog.TXT" for Append Shared as #nFile Print #nFile,format$(Now,"mm-dd hh:mm:ss") & " " & sMessage Close #nFile End Sub
With a few lines of code, you can add a log file to your application.
The function can be called from an error routine or to inform you of a program event:
LogPrint "The database was successfully opened."
The output of the log file can be viewed with a text editor, as shown in Figure 21.5.
Recall from Listing 21.1 (in the preceding section) that you opened the file in Input mode by using the keyword Input. To write data, you open the file for sequential output. However, instead of using the keyword Output, you use Append. Compare the following two lines of code, each of which opens a file for output:
'Append mode adds to an existing file or creates a new one Open "ErrorLog.TXT" for Append as #1 'Output Mode always creates a new file, erases any existing information Open "ErrorLog.TXT" for Output as #1
Append mode means that data written to the file is added to the end of any existing data. This is perfect for the log file application because you want to keep adding to the log file. Opening a file for Output means that any existing data will be erased. In either case, the Open statement automatically creates the file if it does not exist. After a file has been opened for Output, you can use a couple of different statements to write information to it. The Print# and Write# statements, described in the next section, provide different formatting options for sequential files.
Using Print and Write
The Print# statement works almost exactly like the Print method (described in Chapter 20, "Accessing the Windows API"), except that instead of going to an onscreen object, the output is routed to the open file. Unless a semicolon or other separator is at the end of the list of things to be printed, a new line is automatically inserted into the file after each print. The syntax of the Print# statement is the following:
Another statement, the Write# statement, works like the Print# statement, but automatically adds separators and delimiters. The syntax of the Write# statement is the following:
The Write statement is intended for use with the Input# statement, described earlier in the "Reading from a Sequential Text File" section. Some examples of both statements are listed here, and the resulting file is shown in Figure 21.6.
Print #1, "This is an example of Print# and Write#" Print #1, "Siler","Brian" Write #1, "Siler","Brian" Print #1, "Really?", 2*3;Spc(5);"Good."; Write #1,"Date",1/1/1998,1000*5; Print #1, vbCrLf & "Bye!"
Although Print# gives you more control over output format, Write# adds delimiters for easy retrieval of information.