VB6's File System Objects

by Peter G. Aitken

File System Objects (FSO) completely recast Visual Basic’s fundamental powers over disk storage in an object-oriented mold. It makes file access and management considerably easier, even though it isn’t quite complete.

I’ll take an in-depth look at one of the new toys that the Redmondians have provided in VB6: the object-oriented file access and management system, called File System Objects (FSO). This isn’t one of the flashier additions to the new version of Visual Basic, and it certainly has not gotten the same attention as, say, ActiveX Data Objects or Dynamic HTML. Even so, it’s an important improvement to the language, one that you should begin using in your own programs as soon as possible. FSO really doesn’t let you do anything that cannot be done with the old file-oriented commands, but it makes many tasks much easier. Perhaps most important is that FSO moves file access and manipulation from the realm of procedural programming to the modern realm of object-oriented programming, with all the advantages that entails.

There is, however, one fly in the ointment. While the FSO framework for file management (creating folders, moving and deleting files, and so on) seems to be complete, the file access part of FSO (writing data to and reading data from files) is only partially complete. To be precise, you can read and write only sequential text files—for random access and binary files, you are still limited to the traditional Basic statements. I am sure this limitation will be corrected soon, but for now you’ll just have to live with it.

Some of the material in this column is adapted from my newest Coriolis Group book, Visual Basic 6 Programming Blue Book.

Text File Access with FSO

The top dog in the FSO hierarchy is the FileSystemObject class. To read or write a text file, you must first create an instance of this class:

Dim myFSO
Set myFSO = _
CreateObject("Scripting.FileSystemObject")

The following alternate syntax accomplishes the same thing:

Dim myFSO As New Scripting.FileSystemObject

The Scripting qualifier identifies the library in which the FileSystemObject class is defined. To use the class, you do not need to select the Microsoft Scripting Runtime library in the Visual Basic References dialog box, but doing so will give you access to the classes, methods, and properties in the Object Browser. (If you are not familiar with the Object Browser, you owe it to yourself to find out; it is a great source of information about classes.)

After creating an instance of the FileSystemObject class, the next step is to create a TextStream object. A TextStream object is nothing more than a regular text file enclosed in an FSO wrapper. The FileSystemObject has two methods for creating TextStream objects:

  • CreateTextFile creates a new text file. If a file of the same name already exists, it is overwritten.
  • OpenTextFile opens a text file for reading and/or writing. If the file already exists, new data is appended to existing data.

The syntax for these methods is similar. In these examples, assume that myFSO is a FileSystemObject and that it has been declared as a type Variant or Object. The first line of code creates a new file, and the second line opens an existing file:

Set ts = myFSO.CreateTextFile(filename[, overwrite[, unicode]])
Set ts = myFSO.OpenTextFile(filename[, iomode[, create[,_
format]]])

Filename is a string expression specifying the name (including path information) of the file. The overwrite argument is either True or False, indicating whether an existing file will be overwritten. If this argument is omitted, the default is False. If overwrite is False and filename already exists, an error occurs. You can trap this error to permit the user to verify file overwrites. Set unicode to True to create a Unicode file, or False (the default) for an ASCII file. Set iomode to the constants ForReading or ForAppending to read the file or write data to the end of the file, respectively. A file opened using ForReading cannot be written to. Set create to True or False to specify whether a new file will be created if the file named in the filename argument does not exist. The default is False. The format argument is a tristate argument (that is, one that can take on one of three possible values) that determines the format of the file:

  • TriStateTrue opens the file as Unicode.
  • TriStateFalse (the default) opens the file as ASCII.
  • TristateUseDefault uses the system default format setting.

What Is Unicode?

When dealing with text, computers use numbers to represent characters, punctuation marks, and so on. The two most commonly used systems for this are ASCII (or ANSI) and Unicode. ASCII uses one byte per character, permitting only 256 different symbols to be represented. This is adequate for English but cannot support many other languages. Unicode uses 2 bytes per character, permitting over 65,000 different symbols. Which format you use depends on the specific requirements of your project.

Another way to obtain a TextStream object is to create a File object and then use its OpenAsTextStream method. This method works with existing files only. Creating a File object is done like this, assuming that myFSO is a FileSystemObject:

Dim f
Set f = myFSO.GetFile(filename)

If the file does not already exist, you can take the following approach, using CreateTextFile to create the file before creating the File object:

myFSO.CreateTextFile filename
Set f = myFSO.GetFile(filename)

After creating the File object, you can invoke the Open-AsTextStream method. The syntax is:

f.OpenAsTextStream([iomode, [format]])

The iomode and format arguments are the same as described above for the CreateTextFile and OpenTextFile methods. Here’s the code necessary to create a TextStream object associated with an existing file DEMO.TXT for reading, using the OpenAsTextStream method:

Dim myFSO, f, ts
Set myFSO = CreateObject("Scripting.FileSystemObject")
Set f = myFSO.GetFile("demo.txt")
Set ts = f.OpenAsTextStream(ForWriting, _
TristateUseDefault)

Once you have created a TextStream object, you use its properties and methods to write and read text. The object’s properties are listed in Table 1. In reading this table, be aware that the TextStream object always has a current character position, also called the file pointer, that indicates where the next read or write operation will take place. All of these properties are read-only.

Table 1. Properties of the TextStream object.
Property Description
AtEndOfLine True if the file pointer is at the end of a line; False otherwise. This property applies only to TextStream files that are open for reading; otherwise, an error occurs.
AtEndOfStream True if the file pointer is at the end of the file; False otherwise. This property applies only to TextStream files that are open for reading; otherwise, an error occurs.
Column Returns the column number of the file pointer. The first character on a line is at column 1.
Line Returns the current line number.

The TextStream object has a number of methods to read and write data. These methods are described in Table 2.

Table 2. Methods of the TextStream object.
Property Description
Close Closes the file associated with the TextStream object. Always execute the Close method when you are done reading/writing the file.
Read(n) Reads the next n characters from the file and returns the resulting string.
ReadAll Reads the entire file and returns the resulting string.
ReadLine Reads an entire line (up to, but not including, the newline character) from a TextStream file and returns the resulting string.
Skip(n) Skips ahead (moves the file pointer) by n characters.
SkipLine Skips to the beginning of the next line.
Write(s) Writes the string s to the file. No extra or newline characters are added.
WriteBlankLines(n) Writes n blank lines to the file.
WriteLine(s) Writes the string s to the file followed by a newline character.

Be aware that certain of these methods are applicable only when the file has been opened for reading or writing. If you try to use a method that is inappropriate for the file’s mode, an error will occur.

File Management with FSO

As with file access, file management with FSO is based upon the FileSystemObject class. I’ve already shown you how to create an instance of this class. Once you have done this, you can use its properties and methods to perform the file manipulation tasks required by your program.

As mentioned earlier, the FileSystemObject is the “top” object in the FSO hierarchy. As such, it provides access to all of the system’s drives (both local and network), folders, and files. There are several other objects in the hierarchy, and you can see that they correspond to the way in which disk drives are organized:

  • Drive object, which corresponds to a single disk drive on the system.
  • Folder object, which corresponds to a single folder on a drive.
  • File object, which corresponds to a single file in a folder.

The following is a brief overview of how the FSO system works. The FileSystemObject has a Drives collection that contains one Drive object for each local and network drive. You can query a Drive object’s properties to obtain information about the drive, such as its type and the amount of free space. Each Drive object contains a single Folder object representing the drive’s top-level folder, or root. Each Folder object contains a Folders collection and a Files collection. The Folders collection contains a Folder object for each subfolder within the folder, and the Files collection contains a File object for each file in the folder.

The Drives, Folders, and Files collections are like any other Visual Basic collection, and they are used the same way. (I can’t explain collections here, but it’s a good idea for you to understand them because they are used a lot in Visual Basic’s objects.)

Each Drive object has a set of properties (listed in Table 3) that provides information about the physical drive. Except as noted, these properties are all read-only.

Table 3. Drive object properties.
Property Description
AvailableSpace The amount of space available to a user on the specified drive or network share. Generally the same as the FreeSpace property, but may differ on systems that support quotas.
DriveLetter The drive letter associated with the drive. Returns a zero-length string for network drives that have not been mapped to a drive letter.
DriveType A value indicating the type of the drive. Possible values are 0 (unknown), 1 (removable), 2 (fixed), 3 (network), 4 (CD-ROM), and 5 (RAM disk).
FileSystem The type of file system. Available return types include FAT, NTFS, and CDFS.
FreeSpace The amount of space available to a user on the specified drive or network share. Generally the same as the AvailableSpace property, but may differ on systems that support quotas.
IsReady Returns True if the drive is ready, False if not. Used with removable media and CD-ROM drives, returning False if the media has not been inserted.
Path The path of the drive. This consists of the drive letter followed by a colon.
RootFolder Returns a Folder object representing the drive’s root path.
SerialNumber The unique serial number identifying a disk. Use this property to verify that a removable media drive contains the proper media.
ShareName The share name assigned to a network drive. For non-network drives, a zero-length string.
TotalSize The total capacity of the drive.
VolumeName The volume name of the drive. You can write to this property to change a drive’s volume name.

A simple program can demonstrate how to use the Drives collection to obtain information about the drives on the system. Create a Standard EXE project and place a Text Box on the form. Set the Text Box’s Multiline property to True, and set its size to nearly fill the form. Put the code from Listing 1 in the Text Box’s Click event procedure. When you run the program, click on the Text Box control to display a list of the system’s drives and their total and free space.

The Folder Object

A Folder object represents a single folder, or subdirectory, on a drive. You use the object’s methods to copy, move, or delete the folder (as explained below), and you use the object’s properties to obtain information about the folder. Perhaps most important, a Folder object contains two collections, Files and SubFolders, that provide access to the files and subfolders within the folder. Table 4 explains the properties of the Folder object.

Table 4. Properties of the Folder object.
Property Description
DateCreated Date and time the folder was created.
DateLastAccessed Date and time the folder was last accessed.
DateLastModified Date and time the folder was last modified.
Drive Drive letter of the drive where the folder resides.
Files A Files collection containing all the files in the folder.
IsRootFolder True if the folder is the root, False otherwise.
Name Sets or returns the name of the folder.
ParentFolder Returns a Folder object representing the folder’s parent folder.
Path The path of the folder, including drive letter.
ShortName The short name used by programs that require the old 8.3 naming convention.
ShortPath The short path used by programs that require the old 8.3 naming convention.
Size The size, in bytes, of all files and subfolders contained in the folder.
SubFolders A Folders collection containing one Folder object for each subfolder.

Because each Folder object contains information about its parent folder and its subfolders, you can easily traverse the entire folder structure on a drive. This is a powerful tool, as will be demonstrated later. First, however, let’s look at the Folder object’s methods.

The Copy method copies the folder and its contents to a new location. The syntax is as follows (assuming f to be a Folder object):

f.Copy destination[, overwrite]

The destination argument specifies the destination where the folder is to be copied to. Set overwrite to True (the default) to overwrite existing files or folders, or to False otherwise. Note that you can also copy a folder using the FileSystemObject’s CopyFolder method.

The Move method moves the folder and its contents from one location to another. The syntax is:

f.Move destination

Here, destination specifies the destination where the folder is to be moved to. You can also move folders with the FileSystemObject’s MoveFolder method.

The Delete method deletes a folder and its contents. The syntax is:

f.Delete [force]

The optional force argument specifies whether files or folders with the read-only attribute set should be deleted (force = True) or not (force = False, the default). You can also delete folders with the FileSystemObject’s DeleteFolder method.

To demonstrate the power of the Folder object, I created a small utility that counts the total number of files and folders on your C drive. This might seem like a difficult task, but it requires relatively little code. The simplicity of this program is a result of two things: the design of the Folder object and the use of a recursive algorithm. Here’s an outline of how it works:

  1. Get the drive’s root Folder object.
  2. Use the root folder’s Folders collection to access each of its subfolders.
  3. Determine the number of files and subfolders in each subfolder, and add these values to the totals.
  4. Use the subfolder’s Folders collection to access each of its subfolders.
  5. Continue until all subfolders have been processed.

Create a standard EXE project with a single form. Place one Label control and a control array of two Command Buttons on the form. Set the Label’s Caption property to a blank string, and the Command Buttons’ Caption properties to “Start” and “Quit.” Place the following global variable declarations in the General section of the form’s code:

Dim NumFolders As Long, NumFiles As Long

These variables will hold the counts of files and folders. Generally speaking, it’s not good programming practice to use global variables such as these, but for such a simple program, it simplifies our job and will not cause any problems. Next, place the code shown in Listing 2 in the Command Button’s Click event procedure. When the user clicks on the Start button, this code does the following:

  1. Initializes the counter variables to 0.
  2. Disables the Command Buttons so they cannot be clicked while the counting process is in progress.
  3. Displays “Working …” in the Label control.
  4. Calls the procedure CountFilesAndFolders (yet to be written) to perform the count.
  5. When execution returns from the procedure, re-enables the Command Buttons.

The process of counting the files and folders is performed by the procedure CountFilesAndFolders. To be more accurate, the counting process is started by this procedure. The code is shown in Listing 3. Here’s what the code does:

  1. Creates a FileSystemObject.
  2. Loops through the Drives collection until drive C: is found.
  3. Passes the drive’s RootFolder, which you’ll remember is a Folder object, to the procedure DoCount.

The real work of the program is done by the DoCount procedure, shown in Listing 4. Given how much work it does, it is deceptively short. It is here that the power of the recursive algorithm comes into play. DoCount is passed a Folder object as its argument. Then, here’s what it does:

  1. Gets the number of subfolders in the folder and adds it to the folders count.
  2. Gets the number of files in the folder and adds it to the files count.
  3. Calls DoCount for each subfolder in the Folders collection.

Step 3 is where the recursion occurs—when the DoCount procedure calls itself. As this program illustrates, recursion can be a powerful technique for certain tasks. If you don’t believe me, try to write a program that counts the files and folders on a drive without using recursion.

The File Object

Now let’s turn our attention to the final member of the FSO team, the File object. In the FSO model, each file on a disk is represented by a File object. There are two ways to create a File object. If you know the name and path of the file, you can use the FileSystemObject’s GetFile method. Assuming that fs is an instance of the FileSystemObject class:

Dim f
Set f = fs.GetFile(filespec)

The argument filespec contains the filename, including a relative or absolute path. An error occurs if the file called out in filespec does not exist. Note that executing GetFile does not open the file, it simply returns a File object linked to the file.

Another way to obtain a File object is from a Folder object’s Files collection. As you learned earlier, you can create a Folder object for any subfolder on a disk, and the Folder object contains a Files collection containing one File object for each file in the folder. You can write code to iterate through the collection, looking for one or more files that meet a specified criterion. For example, the following code creates an array of File objects containing all the DLL files in the application’s current path:

Dim fs, f, f1, filelist()
Dim i As Integer, j As Integer
i = 0
ReDim filelist(0)
Set fs = CreateObject("Scripting.FileSystemObject")
Set f = fs.GetFolder(App.Path)
For Each f1 In f.Files
If LCase(Right(f1.Name, 3)) = "dll" Then
i = i + 1
ReDim Preserve filelist(i)
Set filelist(i) = f1
End If
Next

Once you create a File object, you have access to all the properties of the file. You can also use the object’s methods for certain types of file manipulation. The methods and properties are explained in Tables 5 and 6.

Table 5. The File object’s methods.
Method Description
Copy dest [, overwrite] Copies the file to dest. An existing file is overwritten only if overwrite is True (the default).
Move dest Moves the file to dest.
Delete [force] Deletes the files. Read-only files are deleted only if force is True. The default is False.
OpenAsTextStream Opens the file and returns a TextStream object.
Attributes  
Table 6. The File object’s properties.
Property Description
Attributes Returns a value summarizing the file’s attributes, as explained in detail below.
DateCreated Date and time the file was created.
DateLastAccessed Date and time the file was last accessed.
DateLastModified Date and time the file was last modified.
Drive Drive letter of the drive where the file resides.
Name Sets or returns the name of the file.
ParentFolder Returns a Folder object representing the file’s parent folder.
Path The path of the file, including drive letter.
ShortName The short filename used by programs that require the old 8.3 naming convention.
ShortPath The short path used by programs that require the old 8.3 naming convention.
Size The size, in bytes, of the file.
Type Returns information about the type of the file.

The Attributes property provides information about the file’s attributes, such as whether it is read-only or a system file. The single value returned by the Attributes property is a composite of the individual attribute values, as shown in Table 7. This table also indicates which of the individual attributes are read/write and which are read-only. You use Visual Basic’s logical operators to convert between individual file attributes and the value of the Attributes property.

Table 7. Component values of the Attribute property.
Attribute Value Description Access
Normal 0 Normal file; no attributes are set  
ReadOnly 1 Read-only file Read/write
Hidden 2 Hidden file Read/write
System 4 System file Read/write
Volume 8 Disk drive volume label Read-only
Directory 16 Folder or directory Read-only
Archive 32 File has changed since last backup Read/write
Alias 64 Link or shortcut Read-only
Compressed 128 Compressed file Read-only

Even though it will take a lot of getting used to, the FSO approach to file access and management is a great improvement over the old methods. Once FSO is expanded to include random access and binary files, you’ll be able to relegate the traditional Basic file-related statements to the dustbin of history.

Listings

The code listings for this article can be found at http://www.pgacon.com/BVColumns/BV16.HTMPopup link


During daylight hours, Peter is a research scientist at Duke University Medical Center in Durham, North Carolina. Comments and suggestions may be sent to him at paitken@acpub.duke.edu

Copyright 1998 The Coriolis Group, LLC. All rights reserved.

©Aivosto Oy -