Since the introduction of the file-system directory in Windows 95, Microsoft has been using directories and folders to organize files, programs, and other items that the OS needs. In the Windows OS, directories and folders differ slightly. Directories can contain only files, whereas folders can contain any type of item, including files, other folders, and custom information. An example of a nonfile, or special, folder is the Printers folder. This folder doesn't contain files but rather items that correspond to the installed printers that users access from their machines.
The File System Object (FSO) model's Folder object is the scripting counterpart of the file-system directory. However, in the context of the FSO hierarchy of objects, directories and folders are the same. Thus, the Folder object works well for accessing and manipulating most of the Windows OS's directories and folders. (For information about accessing and manipulating special folders, see the sidebar "Special Tools for Special Folders.") With the Folder object and its parent, the FileSystemObject object, you can access, create, copy, move, rename, and delete folders and their subfolders.
To access a folder, you need to obtain a reference to the Folder object that represents it. You can obtain this reference only by using the FileSystemObject object's GetFolder method. After you access a folder, you can reference its subfolders in two ways. One approach is to call the Folder object's Folders collection to obtain a list of all the subfolders in that folder. A more common approach is to directly reference a subfolder by specifying its absolute path (i.e., a fully qualified path that contains drive and folder information before the filename). For example, the code
Set fso = CreateObject _ (|Scripting.FileSystemObject") Set fld = _fso.GetFolder(|C:\mydir")
returns the Folder object representing the MyDir folder. You begin this code by using the CreateObject function to instantiate the FileSystemObject object and assigning that instance to a variable. As I mentioned in my January 2000 and February 2000 columns, you must use the CreateObject function every time you create a FileSystemObject object because it is a COM object. However, from this point on, I won't include the
Set fso = CreateObject _ (|Scripting.FileSystemObject")
command in the code examples to save space.
Next, you use the FileSystemObject object's GetFolder method with the folder's absolute path as the argument. You must specify a path that evaluates to an existing folder. If you specify a path to a folder that doesn't exist, you'll receive the error message Path not found.
To avoid this error, you can use the FileSystemObject object's FolderExists method to determine a folder's presence before you call GetFolder. For example, the following code checks for the existence of the folder at the path C:\nodir and displays a warning message if it doesn't exist:
If Not fso.FolderExists _ (|C:\nodir") Then MsgBox |The folder doesn't" _ & |exist." End If
Even if a folder's name terminates with a backslash (e.g., C:\mydir\), this code will correctly detect the folder's presence.
Accessing Folders' Properties
After you have a reference to a Folder object, you can access its properties. You use the syntax
where fldObject is the Folder object you've referenced and Property is the name of the property you want to access. You can use the Folder object's properties to return such information as the folder's type, path, short path, parent folder, file-system attributes, and size.
The Type property returns a string that specifies the folder's type (i.e., the short description that Windows Explorer displays in its Type column). Typically, the Type property returns the string File Folder. However, that's not the case for folders that aren't file-system containers. For example, the Type property returns the string Briefcase for the My Briefcase folder.
The Path property returns a string specifying a folder's absolute path. For example, if you run the code
Set fld = fso.GetFolder _ (|C:\mydir") MsgBox fld.Path
the MsgBox function displays C:\mydir. If you want the 8.3 version of the folder's path (i.e., an 8-character filename with a 3-character extension), you use the ShortPath property instead.
If you want to discover the parent folder of a given Folder object, you use the ParentFolder property. Unlike Path and ShortPath, ParentFolder returns another object, not a string. If the given object is a root folder, ParentFolder returns the Null object because root folders don't have parent folders.
The Attributes property returns a value representing the file-system attributes of status (e.g., normal file, folder) and permissions (e.g., read/write, read-only) for the file-system entry (e.g., a Folder or File object) you specify. For example, if you run the code
Set fld = fso.GetFolder _ (|C:\mydir") MsgBox fld.Attributes
MsgBox displays a value such as 16. This value is the logical bitwise combination of 16+0. (Bitwise means that you act on the individual bits of a value rather than the value as a whole.) As Table 1 shows, 16+0 specifies that MyDir has directory status (bit value of 16) and no permissions set (bit value of 0). All folders have an attributes value of at least 16.
The Attributes property is read/write, so you can use it to not only discover but also change a folder's attributes value. To change it, you use the property's optional newattributes argument, which has the syntax
fldObject.Attributes _ \[= newattributes\]
where newattributes is the new attributes value you want the folder to have. For example, to change the MyDir folder's status to read-only, you specify 17 (i.e., 16+1) as the argument with the code
Set fld = fso.GetFolder _ (|C:\mydir") fld.Attributes = 17
Although you can change a folder's permissions, you can't change its status because the Windows OS can't transform folders into files. Thus, when you set an attributes value for a Folder object, the FileSystemObject object doesn't consider the status bit value. Therefore, you can change an attributes value by simply specifying the new permission bit value with code such as
Set fld = fso.GetFolder _ (|C:\mydir") fld.Attributes = 1
An interesting behavior takes place when you use the Size property. This read-only property returns the global size, in bytes, of all the files and subfolders in a folder. However, the Folder object doesn't read this information but rather calculates it with a recursive algorithm. Thus, the Folder object takes a while to return the correct value. Fortunately, the Folder object internally caches this value and immediately returns it in any successive calls to the Size property.
The Type, Path, ShortPath, ParentFolder, Attributes, and Size properties are only a few of the Folder object's many properties. You can learn about the rest from the Scripting Run-Time Library Reference on the Microsoft Developer Network (MSDN) at http://msdn.microsoft.com/scripting/vbscript/doc/vbsfsotocalt.htm.
To create folders, you use the FileSystemObject object's CreateFolder method. CreateFolder takes one argument: the new folder's path. You can use an absolute path or a relative path (i.e., an incomplete path that might not include the drive or parent folder).
When you use an absolute path, the FileSystemObject object creates a folder at the location you specify. For example, the code
creates a root folder named NewDir on the C drive. When you use a relative path with code such as
the FileSystemObject object creates the folder in the current folder. Typically, the current folder is the one from which you're running the script.
No matter which method you use, you can create just one level of folders. If you specify a path such as
you'll receive the error message Path not found (unless you have a folder named One). If you successfully create the folder then try to run the same script again, you'll receive the error message File already exists.
Although the FSO model doesn't have a direct method to create nested folders, you can use a VBScript function I created called MakeSureDirectoryTreeExists. You can find this function in the Code Library on the Win32 Scripting Journal Web site at http://www.win32scripting.com.
Copying and Moving Folders
Both the FileSystemObject and Folder objects expose methods that let you copy and move folders. In other words, you can use either object to obtain the same result.
Using the FileSystemObject object. To copy and move folders with the FileSystemObject object, you use its CopyFolder and MoveFolder methods. As the syntax
fsoObject.CopyFolder source, _ destination \[, overwrite\]
shows, CopyFolder has two mandatory arguments and one optional argument. The source argument contains the absolute path of the folder you're copying (i.e., the source folder). The destination argument contains an absolute path that points to where you want to copy the source folder (i.e., the destination folder).
If the destination folder doesn't exist, the FileSystemObject object automatically creates the folder and copies the source folder's contents into it. If the destination folder exists, the FileSystemObject object automatically overwrites that folder's existing contents.
If you don't want to overwrite content, you can set the optional overwrite argument to False. However, you'll receive the error message File already exists at each name conflict unless you use exception handling to avoid these errors. (See my September column for more information about exception handling.) If you want to automatically overwrite content, you don't have to include the argument in your code because the argument's default is True.
You can use the asterisk (*) and question mark (?) wildcards in the source argument but only in its final element (i.e., in the folder's name). The asterisk is a placeholder for any number of characters, whereas the question mark replaces just one character. For example, the code
fso.CopyFolder _ |C:\mydir\*.bmp", _ |D:\mynewdir"
copies all the .bmp files in the MyDir folder to the MyNewDir folder.
If the destination folder exists, you can append a backslash (\) to the end of the destination argument to tell the FileSystemObject object to start a new subtree underneath the existing destination folder. For example, the code
fso.CopyFolder |C:\mydir", _ |D:\mynewdir\"
creates the MyDir subtree under D:\mynewdir.
To move objects, you use the FileSystemObject object's MoveFolder method. As the syntax
fso.MoveFolder source, _ destination
shows, MoveFolder has the same mandatory arguments as CopyFolder but doesn't have the optional overwrite argument. Like CopyFolder, MoveFolder supports wildcards in the source argument and a final backslash in the destination argument.
Using the Folder object. The Folder object's Copy and Move methods have a slightly simplified syntax compared with the FileSystemObject object's counterparts. As the syntax
fldObject.Copy destination _ \[, overwrite\]
show, Copy and Move don't have a source argument. The FileSystemObject object doesn't need this argument because it already knows the source folder: the Folder object from which you're calling the method. For example, to copy C:\mydir to D:mynewdir, you use the code
Set fld = _ fso.GetFolder(|C:\mydir") fld.Copy |D:\mynewdir"
You can't use wildcards when copying or moving files with the Folder object. However, you can append a backslash to the end of the destination argument to start a new subtree underneath the existing destination folder.
The FSO model doesn't include a method for renaming a folder. However, because the Folder object's Name property is read/write, you can use that property to rename a folder. For example, to rename C:\mydir to C:\mydir1, you use the code
Set fld = fso.GetFolder _ (|C:\mydir") fld.Name = |C:\mydir1"
You can use the FileSystemObject object's DeleteFolder method or the Folder object's Delete method to delete folders. As the following code shows, DeleteFolder takes one mandatory argument, foldername, which contains the name of the folder you want to delete:
If you want to delete several folders simultaneously, you can use wildcards in the last element of the foldername argument.
You can use DeleteFolder's optional force argument to force the deletion of read-only folders. By default, the FileSystemObject object sets this flag to False, which means don't delete.
The Folder object's Delete method doesn't take any arguments because you're calling this method from the Folder object you want to delete. For example, to delete the MyDir folder, you specify
set fld = fso.GetFolder _ (|C:\mydir") fld.Delete
The DeleteFolder and Delete methods treat the deletion of empty folders and nonempty folders the same way. When you delete a folder that contains files, you can't recover those files later because those files don't go to the Recycle Bin.
The FSO Story Continues
A folder is a container that typically holds files and subfolders. You now know how to use the FolderSystemObject and Folder objects to access and manipulate subfolders. Next month, I'll show you how to access and manipulate files with the FSO model's File object.