Working with Drives and Directories
On a Windows computer, persistent storage—in other words, disk drives—is organized into directories (also called folders). Each drive has a single root directory. The root directory may have one or more subdirectories. Those subdirectories may in turn have their own subdirectories, and so on. Network sharing introduces additional complexity. You can refer to shared network drives and directories by using their share name (for example, \\MainServer\MyFolder) or a mapped drive letter. Following are some of the tasks related to drives and directories that you may need to perform in your .NET programs:
- Determining what drives exist
- Determining whether a specific directory exists
- Creating, moving, and deleting directories
- Setting the current directory
The .NET Framework provides two classes for performing these tasks. The Directory class exposes static (shared) methods for working with directories, whereas the DirectoryInfo class provides instance methods. (This is the same as the distinction between the FileInfo and File classes.) Both classes are part of the System.IO namespace.
Because the file system treats a directory as a special kind of file, many class members that are available in the File and FileInfo classes are also present in the Directory and DirectoryInfo classes. Specifically, FileInfo members that are also present in DirectoryInfo are as follows:
- CreationTime
- Delete
- LastAccessTime
- LastWriteTime
- MoveTo
The DirectoryInfo class constructor takes as its one argument a string that specifies the target directory. Here’s the syntax:
New(path)
where path is a string giving the path of the directory. An exception will be thrown if the directory doesn’t exist, if the path string isn’t properly formed, if the user doesn’t have the required permission, or if the path is longer than 256 characters. Here’s an example of creating an instance of this class:
Dim d As New DirectoryInfo("c:\documents")
The Directory and File classes also have some members in common:
- Delete
- GetCreationTime
- GetLastAccessTime
- GetLastWriteTime
- Move
Table 2 shows some additional members of the Directory class; Table 3 describes additional members of the DirectoryInfo class.
Table 2 Additional members of the Directory class.
Class Member |
Description |
CreateDirectory(path) |
Creates the specified directory and, if necessary, the path to it. Returns a type DirectoryInfo for the new directory. |
GetCurrentDirectory() |
Returns a type String containing the path of the current working directory. |
GetDirectories(path) |
Returns, in an array of type String, the names of all subdirectories in the directory specified by path. |
GetDirectoryRoot(path) |
Returns the volume and root information for the specified directory (for example, "c:\"). |
GetFiles(path) |
Returns, in an array of type String, the names of all files in the specified directory. |
GetFileSystemEntries(path) |
Returns, in an array of type String, the names of all files and subdirectories in the specified directory. |
GetLogicalDrives() |
Returns, in an array of type String, all the logical drives on the system, in the form "<drive letter>:\". |
GetParent(path) |
Returns a type DirectoryInfo referencing the parent of the specified directory). |
SetCurrentDirectory(path) |
Sets the application’s working directory to the specified directory. |
Table 3 Additional members of the DirectoryInfo class.
Class Member |
Description |
Parent |
Returns a type DirectoryInfo referring to the parent directory of the instance directory. |
Root |
Returns a type DirectoryInfo referring to the root directory. |
CreateSubdirectory(path) |
Creates the subdirectory specified by path and returns a type DirectoryInfo referring to the new directory. |
GetDirectories() |
Returns an array of type DirectoryInfo containing references to all of the subdirectories in the instance directory. |
GetFiles() |
Returns an array of type FileInfo containing references to all of the files in the instance directory. |
Notice that the Directory class has methods for getting and setting the current working directory. What exactly is this?
Any running application has a working directory, which is where the application’s file operations (such as opening a file) will occur by default—that is, if no path is specified for the operation. The working directory is also the location from which relative path specifications are determined. During program development in Visual Studio, the working directory is by default the bin directory within the project directory. After deployment, it’s the directory where the application’s .exe file is located. It’s rarely a good idea to rely on the default working directory, however, so your code should either change the working directory or always specify the complete path for file operations.
Let’s wrap up this article with some examples of using the Directory and DirectoryInfo classes.
The following code uses the Directory class to display, in the immediate window, a list of all subdirectories in the c:\documents directory:
Dim sa() As String Dim s As String sa = Directory.GetDirectories("c:\documents") For Each s In sa Debug.WriteLine(s) Next
This code performs the same task, but uses the DirectoryInfo class:
Dim d As New DirectoryInfo("c:\documents") Dim da() As DirectoryInfo Dim x As DirectoryInfo da = d.GetDirectories For Each x In da Debug.WriteLine(x.FullName) Next
The next example checks to see whether a specified directory exists. If so, a message to that effect is displayed. If not, the directory is created.
Const DIR_PATH = "c:\my_new_documents" If Directory.Exists(DIR_PATH) Then MsgBox(DIR_PATH & " already exists.") Else Directory.CreateDirectory(DIR_PATH) MsgBox(DIR_PATH & " created successfully.") End If
For a final demonstration, I’ll show you how to determine the total number of files in a directory and all of its subdirectories, along with their total size (see Listing 1). The program makes use of a powerful technique called recursion, whereby a function calls itself repeatedly to carry out a repetitive task. Here’s how it works. The function, called FilesInDirectory(), is passed a type DirectoryInfo referencing the directory of interest. Code in the function obtains a list of all files in that directory and gets the count and total size of these files, adding them to a summary (maintained in a structure that’s defined in the code). Then the code gets a list of all subdirectories that the current directory contains, and calls itself for each one. As a result the code "worms" its way down through all levels of subdirectories, and gets the file information for each one. Recursion is not used all that often, but in appropriate situations it’s a very powerful programming technique.
Listing 1 Using recursion to list files and their sizes.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim result As FileSummary Dim msg As String result = FilesInDirectory(New DirectoryInfo("c:\documents")) msg = "The directory and its subdirectories contain " msg &= result.Count.ToString & " files totaling " msg &= result.TotalSize.ToString & " bytes." MsgBox(msg) End Sub Private Function FilesInDirectory(ByVal d As DirectoryInfo) As FileSummary ’ Returns the total number and total size of files in d ’ and all of its subdirectories. Dim fs1 As New FileSummary() Dim fs2 As New FileSummary() Dim fa() As FileInfo Dim f As FileInfo ’ Get the files in this directory. fa = d.GetFiles ’ Add their info to the summary. For Each f In fa fs1.Count += 1 fs1.TotalSize += f.Length Next ’ Now do the same for all the subdirectories. Dim da() As DirectoryInfo Dim d1 As DirectoryInfo da = d.GetDirectories For Each d1 In da fs2 = FilesInDirectory(d1) fs1.Count += fs2.Count fs1.TotalSize += fs2.TotalSize Next ’ Return the current totals. Return fs1 End Function Structure FileSummary Public TotalSize As Long Public Count As Integer End Structure