No matter what type of scripting you do, it seems like you always have a need to work with text files. Whether you’re monitoring files or maintaining a log, reading and writing text files is a must. WSH is no different. It provides several methods for making your life easier. It even provides a few that you may not have expected. Let’s take a look.
Text files have many different uses: data storage, logging, and program configurations just to name a few. Sometimes this is done in an unformatted text file like a raw data dump or simple log file; sometimes it’s formatted like comma- and tab-delimited files; and sometimes it’s structured like INF files. In any of these cases, the one thing that remains the same is that we are working with plain text.
While the methods provided by WSH only allow us to work with plain text files, the use of third party controls can allow us to work with formatted files such as Microsoft Word documents.
Let’s begin by creating a plain text file to work with. We’ll create a sample data file that contains comma-delimited addresses. Each record is on a new line. For simplicity I’m not going to add a header record. Many files will include one. This is just a line that contains the title of each column.
Any time you start thinking about working with files, you should automatically be thinking of WSH’s FileSystemObject. This is WSH’s way of allowing us to work with files and folders. So, naturally, we’ll begin our script by connecting to the FileSystemObject.
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("C:\addresses.txt", 1)
Do Until objFile.AtEndOfStream
strContents = strContents & objFile.Read(1)
Loop
Wscript.Echo strContents
objFile.Close
This simple code snippet opens a text file and reads it to the end one character at a time. Let’s take a look at the methods we used.
In the second line, the OpenTextFile method opens the text file ForReading and returns it as a TextStream object. The second parameter accepts an Iomode constant depending on how we want to open the file. The default is ForReading.
Table 1: Constant Values for Iomode Attribute
Constant
Value
Description
ForReading
1
Read-Only
ForWriting
2
Allow writing, overwrite contents
ForAppending
8
Allow writing, append to file rather than overwrite
Table 2: Tristate Values for Format Attribute
Constant
Value
Description
TristateTrue
-1
Unicode
TristateFalse
0
ASCII
TristateUseDefault
-2
Use system default
Next, set up a loop to move through the text file. The AtEndOfStream property tells our script when it reaches the end of the text stream. The Read method is used to read the contents of the text file one character at a time.
The Read method returns a string containing the characters read from a text file. It accepts a single integer for a parameter indicating how many characters to read.
The TextStream Object’s Read method will return all characters it finds including whitespace characters such as carriage returns and line feeds.
The example script ends by Echoing back the entire text file as one string. Finally, the Close method is used to close the text stream.
Sometimes reading one character at a time just isn’t very useful or is inefficient. For those times, the TextStream Object provides a few more methods.
Methods:
object.ReadLine
object.ReadAll
object.Skip(Int)
object.SkipLine
Properties:
object.AtEndOfLine
object.Column
object.Line
The ReadLine method will read until it finds an end of line character (vbCr, vbLf, or vbCrLf) and return a string containing the characters excluding the line ending. The ReadAll method will read every character until it reaches an EOF marker before returning its findings as a string (including end of line indicators).
Exercise caution when using the ReadAll method with large files. You can run out of memory which will result in errors during execution.
The Skip method accepts an integer as its parameter and will skip reading the specified number of characters. The SkipLine method can be used to skip an entire line or continue until the next end of line indicator.
Several properties are also available that can help you determine where the file pointer is in a file. AtEndOfLine works in much the same way as AtEndOfStream except that it returns a Boolean value indicating whether the file pointer is at an end of line indicator.
The Column property returns an integer indicating the position of the file pointer in the current line. The first character of the line is position 1. The Line property returns the current line number. The first line in the file is line 1.
Simply reading a text file is generally not enough. You will usually need to be able to work with the data you find. This is called parsing. Parsing can be an extremely arduous task depending on the type of data you are working with and how you want to manipulate it.
I want to present a couple of quick advanced techniques that you will probably find useful as well as a couple of tips to keep in mind when developing your own solutions.
You can only read text files from top to bottom in one pass. There is no way to move back up through a text file.
Text files, especially log files, can become very large, very quickly. If you are processing large amounts of information it can be helpful to know what size your text file is before you begin—more specifically to know that it’s not empty! Here is a modification to our example that employs a little error checking to make sure our text file actually contains data to prevent Read errors.
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = GetFile(“C:\addresses.txt”)
If objFile.Size > 0 Then
Set objReadFile = objFSO.OpenTextFile("C:\addresses.txt", 1)
Do Until objReadFile.AtEndOfStream
strContents = strContents & objFile.Read(1)
Loop
Wscript.Echo strContents
objFile.Close
Else
Wscript.Echo “File is empty.”
End If
Frequently you will be reading text files for the purpose of finding specific data. Often this is much easier if we read our text file into an array first. In this example we are going to return the fourth record from our example text file.
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = GetFile(“C:\addresses.txt”)
If objFile.Size > 0 Then
Set objReadFile = objFSO.OpenTextFile("C:\addresses.txt", 1)
i = 1
Do Until objReadFile.AtEndOfStream
Redim Preserve arrData(i)
arrData(i) = objFile.ReadLine
i = i + 1
Loop
objFile.Close
strContents = arrData(4)
End If
One of the most common uses for reading a text file is to check logged data. Frequently that data is updated by appending information to an existing file which means that the newest data is at the bottom.
If you were reading a text file and wanted to know the most recent action, you would first have to read through the whole file to find the last line. In cases like this it is much easier to process the file in reverse order.
Watch how we can modify our array example so that it processes a file one line at a time from the bottom up.
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = GetFile(“C:\addresses.txt”)
If objFile.Size > 0 Then
Set objReadFile = objFSO.OpenTextFile("C:\addresses.txt", 1)
i = 1
Do Until objReadFile.AtEndOfStream
Redim Preserve arrData(i)
arrData(i) = objFile.ReadLine
i = i + 1
Loop
objFile.Close
For l = Ubound(arrData) to LBound(arrData) Step -1
Wscript.Echo “Record”, l, “=”, arrData(l)
Next
End If
That wraps up part one of this three part series. In the next part I’ll show you how to write to text files. So, until next time, keep coding!