Directory Access
Up to this point, most of your work has involved accessing and maintaining the central
repositories of information that feed Web sites. Database activity is one of the central
activities in site content management, involving the collection, organization, storage,
retrieval, and maintenance of the primary content appearing on Web pages. Yet, there are
other important surrounding tasks that go along with database management. Particularly,
you need to set up and work with the directory and file structures within which all this
activity takes place.
It may be that you have direct physical access to the Web server that hosts your site.
If this is the case, then you can sit down at the server console and create and manage the
folders and files you need. If you are hosted by a remote Internet Service Provider (ISP), you
probably have FTP access to your main Web directory to which you can transfer files and
otherwise work with your site structure. A third option is to create your own Web pages
to handle directory and file access, much in the same way that your pages handle database access.
In fact, ASP.NET supplies a collection of software classes that
permit you to work with your site structure and its contents through your own Web pages
in nearly identical fashion to having direct console or FTP access. It is not necessary to
rely on physical access or third-party hosts to manage your site.
The directory structure assumed previously for working with the BooksDB.mdb
database and associated pictures is continued here. Recall that the main Web directory is on
the physical path c:\eCommerce and that all Web pages appear in the
c:\eCommerce\WebSite subdirectory. All databases and files are in the
c:\eCommerce\Databases subdirectory and all book pictures are in the
c:\eCommerce\BookPictures subdirectory. Therefore, the relative path
from a Web page to the main directory is Server.MapPath(../), the relative
path to the Databases directory is
Server.MapPath(../Databases), and the relative path to the BookPictures
directory is Server.MapPath(../BookPictures). (See Figure 3-8
for an illustration of this directory structure.)
The Directory Class
The ASP.NET Directory class is your access to the directory
structure of your site and its applications. Through various methods supplied by this class,
scripts can manipulate directories in much the same way as you do this locally through the Windows
Desktop and Windows Explorer. That is, you can create and delete directories, view the contents
of directories, and move and copy directories. With proper permissions, you can work remotely
with your directory structure through a Web page just as if your were sitting at the server console.
Directory access is provided through the SystemIO namespace which
must be imported for any page using the Directory class.
<%@ Import Namespace="System.IO" %>
Listing 10-1. Importing a namespace for working with directory system.
Also, you need to be very cautious when using Directory methods.
They can easily erase your entire directory structure with no recourse for getting it back.
Determining Directory Content
The contents of a directory can be determined with three methods shown in Figure 10-1.
Figure 10-1. General formats for accessing directory contents.
The GetDirectories() method returns the paths to all
subdirectories inside the specified directory; the GetFiles()
method returns the paths to all files within the specified directory; the
GetFileSystemEntries() method returns the paths to all folders and files within
a specified directory.
All of these Directory methods return an array of strings, each element of which is the
physical path to a folder or file. Therefore, you need to set up an array to capture the paths, and
a loop to extract them individually from the array. Figure 10-2 shows the general structure of a
script to build and extract elements from an array populated by Directory methods.
Figure 10-2. General formats for retrieving and displaying directory contents.
Displaying Subdirectory Paths
The Directory.GetDirectories() method returns an array of paths to all
subdirectories within a specified directory. The following script illustrates how to retrieve and
displays all of the subfolders inside the eCommerce folder used for many
of the examples in these tutorials.
Figure 10-3. Listing of subdirectory paths inside a directory.
<%@ Import Namespace="System.IO" %>
<SCRIPT Runat="Server">
Sub Show_Folders (Src As Object, Args As EventArgs)
'-- Get directory listing into an array
Dim FolderArray() As String
FolderArray = Directory.GetDirectories("c:\eCommerce")
'-- Iterate the array items and display directory paths
Dim Folder As String
For Each Folder in FolderArray
Folders.Text &= Folder & "<br/>"
Next
End Sub
</SCRIPT>
<form Runat="Server">
<b>Show eCommerce SubFolders: </b>
<asp:Button Text="Show Folders" OnClick="Show_Folders" Runat="Server"/>
<p><asp:Label id="Folders" EnableViewState="False" Runat="Server"/></p>
</form>
It is sometimes useful just to get a list of the folder or file names without the
complete path. This is easily accomplished by using the Visual Basic
Replace() method to remove the path portions of the names. In the following
script only the names of the files in a directory are reported.
<%@ Import Namespace="System.IO" %>
<SCRIPT Runat="Server">
Sub Show_Contents (Src As Object, Args As EventArgs)
Dim ContentsArray() As String
ContentsArray = Directory.GetFileSystemEntries("c:\eCommerce")
Dim Item As String
For Each Item in ContentsArray
Item = Replace(Item, "c:\eCommerce\", "")
Contents.Text &= Item & "<br/>"
Next
End Sub
</SCRIPT>
<form Runat="Server">
<b>Show Directory Contents: </b>
<asp:Button Text="Get Contents" OnClick="Show_Contents" Runat="Server"/>
<p><asp:Label id="Contents" EnableViewState="False" Runat="Server"/></p>
</form>
Listing 10-6. Code to get listing of all contents in a directory.
You might consider producing a general-purpose form for viewing the contents of any directory
entered into a textbox. This application is shown below wherein a default directory is pre-entered
into the textbox. You can, however, view the contents of the Databases,
BookPictures, and WebSite subdirectories by
appending these folder names to the path.
Figure 10-8. Page to view the contents of specified directories.
<%@ Import Namespace="System.IO" %>
<SCRIPT Runat="Server">
Sub Show_Contents (Src As Object, Args As EventArgs)
If Left(Path.Text, 12) = "c:\eCommerce" Then
Try
Dim ContentsArray() As String
ContentsArray = Directory.GetFileSystemEntries(Path.Text)
Dim Item As String
For Each Item in ContentsArray
Item = Replace(Item, Path.Text & "\", "")
Contents.Text &= Item & "<br/>"
Next
Catch
Contents.Text = "• Invalid path"
End Try
Else
Contents.Text = "• Invalid path"
End If
End Sub
</SCRIPT>
<form Runat="Server">
<p><b>Show Directory Contents: </b></p>
<b>Path: </b><asp:TextBox id="Path" Text="c:\eCommerce" Runat="Server"/>
<asp:Button Text="Get Contents" OnClick="Show_Contents" Runat="Server"/>
<p><asp:Label id="Contents" EnableViewState="False" Runat="Server"/></p>
</form>
Listing 10-7. Code to view the contents of specified directories.
There are a couple of tests to make sure that proper directory paths are entered. First,
the input path (Path.Text) is checked to make sure that it begins with
with the characters "c:\eCommerce" in order to restrict listings to
this particular root directory. Also, retrieval and display are contained inside a
Try...Catch block to trap any script execution errors. For example, entering the path
"c:\eCommerce\Database" (rather than "Databases")
produces an error that otherwise would abort the script and display a system error on screen.
Displaying Directory Structures and Files
With a bit more elaborate coding you can automatically produce an entire directory
structure as a set of links to view files in any of the directories. This approach is used in
the following example that maps the structure of the c:\eCommerce
directory.
Figure 10-9. Page to view the contents of all directories.
This application is based on the use of an <asp:PlaceHolder>
and the building of dynamic LinkButton controls for the main directory and each of its subdirectories
(and any of their subdirectories). These LinkButtons call a subprogram to display the file contents
of the directories.
<%@ Import Namespace="System.IO" %>
<SCRIPT Runat="Server">
Sub Page_Load
ViewState("Folder") = "c:\eCommerce"
Create_RootFolder_Link
Create_SubFolder_Links
End Sub
Create_RootFolder_Link
PHFolders.Controls.Clear()
'-- Get folder name
Dim FolderName As String = ViewState("Folder")
Dim SlashPos As Integer = InStrRev(FolderName, "\")
FolderName = Right(FolderName, Len(FolderName) - SlashPos)
'-- Create root folder link
Dim FolderLink As New LinkButton
FolderLink.Text = FolderName
FolderLink.CommandName = ViewState("Folder")
AddHandler FolderLink.Command, AddressOf Show_Files
PHFolders.Controls.Add(FolderLink)
'-- Create line break
Dim LineBreak As New Literal
LineBreak.Text = "<br/>"
PHFolders.Controls.Add(LineBreak)
End Sub
Sub Create_SubFolder_Links
Dim FolderArray() As String
FolderArray = Directory.GetDirectories(ViewState("Folder"))
Dim FolderPath As String
For Each FolderPath in FolderArray
'-- Get folder name
Dim SlashPos As Integer = InStrRev(FolderPath, "\")
Dim FolderName As String = Right(FolderPath, Len(FolderPath) - SlashPos)
'-- Determine number of indention spaces
Dim SlashCount As Integer = 0
Dim i As Integer
For i = 1 To Len(FolderPath)
If Mid(FolderPath, i, 1) = "\" Then
SlashCount += 1
End If
Next
Dim Spaces As String = ""
For i = 1 To SlashCount - 1
Spaces &= " "
Next
'-- Create indention spaces
Dim Spacing As New Literal
Spacing.Text = Spaces
PHFolders.Controls.Add(Spacing)
'-- Create subdirectory link
Dim FolderLink As New LinkButton
FolderLink.Text = FolderName
FolderLink.CommandName = FolderPath
FolderLink.EnableViewState = False
AddHandler FolderLink.Command, AddressOf Show_Files
PHFolders.Controls.Add(FolderLink)
'-- Create line break
Dim LineBreak As New Literal
LineBreak.Text = "<br/>"
PHFolders.Controls.Add(LineBreak)
'-- Reset folder path and recall this subprogram
ViewState("Folder") = FolderPath
Create_SubFolder_Links
Next
End Sub
Sub Show_Files (Src As Object, Args As CommandEventArgs)
Dim FileArray() As String
FileArray = Directory.GetFiles(Args.CommandName)
Dim File As String
For Each File in FileArray
File = Replace(File, Args.CommandName & "\", "")
Files.Text &= File & "<br/>"
Next
End Sub
</SCRIPT>
<form Runat="Server">
<p><b>Show Directory Contents: </b></p>
<table border="0" cellpadding="3" style="width:100%">
<tr style="text-align:left; background-color:#E0E0E0">
<th>Directories:</th>
<th>Files:</th>
</tr>
<tr style="vertical-align:top">
<td style="width:50%">
<asp:PlaceHolder id="PHFolders" Runat="Server"/>
</td>
<td style="width:50%>
<asp:Label id="Files" EnableViewState="False" Runat="Server"/>
</td>
</tr>
</table>
</form>
Listing 10-8. Code to view the contents of all directories.
As you can see from the listing, output is arranged in a table, the left column of which houses
the PlaceHolder containing dynamically-built directory links, and the right column of which contains
a Label for display files in the chosen directory.
As dynamic controls, the LinkButtons must be created on every page-load and post-back. Therefore,
their creation is governed by the Page_Load subprogram.
Sub Page_Load
ViewState("Folder") = "c:\eCommerce"
Create_RootFolder_Link
Create_SubFolder_Links
End Sub
Listing 10-9. Code to initiate building of directory structure.
The top-level directory for this particular listing is assigned to a ViewState variable as the
starting point for creating LinkButtons. You can, in fact, choose any initial directory path when
using this application. Then, the Create_RootFolder_Link subprogram is
called to create the single LinkButton for this root directory; subprogram
Create_SubFolder_Links is called to create the lower-level links.
Create_RootFolder_Link
PHFolders.Controls.Clear()
'-- Get folder name
Dim FolderName As String = ViewState("Folder")
Dim SlashPos As Integer = InStrRev(FolderName, "\")
FolderName = Right(FolderName, Len(FolderName) - SlashPos)
'-- Create root folder link
Dim FolderLink As New LinkButton
FolderLink.Text = FolderName
FolderLink.CommandName = ViewState("Folder")
AddHandler FolderLink.Command, AddressOf Show_Files
PHFolders.Controls.Add(FolderLink)
'-- Create line break
Dim LineBreak As New Literal
LineBreak.Text = "<br/>"
PHFolders.Controls.Add(LineBreak)
End Sub
Listing 10-10. Code for Create_RootFolder_Link subprogram.
Since the links are built each time the page loads, the PlaceHolder is cleared of its controls
so that new links are not added to those created on previous page loads.
The link text appearing on the page is the folder name, which must be extracted from the path to this
folder held in ViewState("Folder"); that is, "eCommerce"
must be extracted from "c:\eCommerce". This is a matter of locating
the final back-slash character ("\") in the path and extracting the remaining
string to its right.
A LinkButton for this folder is created as a new LinkButton control. Then, its
Text property is set to the folder name previously extracted from the path string. The
CommandName for the LinkButton is the full path to the folder: ViewState("Folder"). The subprogram called when this button is clicked is
Show_Files. When this subprogram is called, the
CommandName is passed as an argument to the subprogram, which displays the files contained
on this directory path.
After adding the LinkButton to the PlaceHolder, the script adds a final Literal control whose
Text property is a <br/> tag to produce
a line break following the folder name.
Once this initial LinkButton is created, a call is made to subprogram
Create_SubFolder_Links in order to build links to all subdirectories under the root
directory. The structure of this subprogram is similar to the
Create_RootFolder_Link subprogram with the main difference being that it repeatedly
calls itself to traverse the subdirectories of the root directory. It is a recursive
subprogram.
Sub Create_SubFolder_Links
Dim FolderArray() As String
FolderArray = Directory.GetDirectories(ViewState("Folder"))
Dim FolderPath As String
For Each FolderPath in FolderArray
'-- Get folder name
Dim SlashPos As Integer = InStrRev(FolderPath, "\")
Dim FolderName As String = Right(FolderPath, Len(FolderPath) - SlashPos)
'-- Determine number of indention spaces
Dim SlashCount As Integer = 0
Dim i As Integer
For i = 1 To Len(FolderPath)
If Mid(FolderPath, i, 1) = "\" Then
SlashCount += 1
End If
Next
Dim Spaces As String = ""
For i = 1 To SlashCount - 1
Spaces &= " "
Next
'-- Create indention spaces
Dim Spacing As New Literal
Spacing.Text = Spaces
PHFolders.Controls.Add(Spacing)
'-- Create subdirectory link
Dim FolderLink As New LinkButton
FolderLink.Text = FolderName
FolderLink.CommandName = FolderPath
FolderLink.EnableViewState = False
AddHandler FolderLink.Command, AddressOf Show_Files
PHFolders.Controls.Add(FolderLink)
'-- Create line break
Dim LineBreak As New Literal
LineBreak.Text = "<br/>"
PHFolders.Controls.Add(LineBreak)
'-- Reset folder path and recall this subprogram
ViewState("Folder") = FolderPath
Create_SubFolder_Links
Next
End Sub
Listing 10-11. Code for Create_SubFolder_Links subprogram.
The first step is to get all subdirectories subordinate to root folder
ViewState("Folder"), assigned here to FolderArray(). Then the
elements of FolderArray() are iterated to build a LinkButton for each
directory path in the array. As before, this means assigning the folder name as the LinkButton Text, assigning the full path as the CommandName,
and creating a command link to subprogram Show_Files. Then, this LinkButton
and a trailing line break are added to the PlaceHolder.
When adding links to the PlaceHolder, spaces are used to indent the links to visually represent
the directory structure. Each level is indented three additional spaces. The amount of indention is
given by the number of back-slash characters appearing in a path. Loops are set up to count the
number of these characters and then to build a string of spaces (variable
Spaces) representing this amount of indention. (One fewer than the total number of
back-slashes is used to add spacing since the root path itself contains a back-slash that is
not spaced.)
The final step in the iteration is to reassign to ViewState("Folder")
the current directory for which a LinkButton was just created, then to re-call subprogram
Create_SubFolder_Links. The purpose is to iterate and create LinkButtons
for any subdirectories of the current directory prior to returning to the iteration and
continuing through the original directory. This recursive calling of the subprogram proceeds through
as many levels of subdirectories as are subordinate to the root directory.
Once the structure of LinkButtons is created, each is clicked to call subprogram
Show_Files. Notice that this subprogram has the appropriate signature for a call by a command
button (CommandEventArgs).
Sub Show_Files (Src As Object, Args As CommandEventArgs)
Dim FileArray() As String
FileArray = Directory.GetFiles(Args.CommandName)
Dim File As String
For Each File in FileArray
File = Replace(File, Args.CommandName & "\", "")
Files.Text &= File & "<br/>"
Next
End Sub
Listing 10-12. Code for Show_Files subprogram.
Recall that the CommandNames assigned to LinkButtons are paths to
the named directories. Therefore, argument Args.CommandName is the path
identifying which directory's files to display: Directory.GetFiles(Args.CommandName).
As in previous examples, the retrieved file paths are assigned to an array which is iterated to display
the file names. File names are extracted from the paths by replacing the directory-path portion of the
file-path string.
Creating and Deleting Directories
The Directory class provides two methods used to create and delete
directories under script control. Their general syntax is shown in Figure 10-10.
Figure 10-10. General formats for creating and deleting directories.
The path is the physical path to a folder or a relative path
converted to a physical path with Server.MapPath(). This
path can be a literal string or a reference to a variable containing a path string.
When creating directories, all directories on the path to the final directory are also created if
they do not exist. If the named directory already exists, it is not created.
When deleting a directory, the True or False
parameter specifies whether to delete the directory if it contains subdirectories and/or files. The
default value is False, meaning that the folder must be empty to be
deleted. If True is specified, the directory and its subfolders
and files are deleted.
Creating Directories
A directory is created by including its name on the path of the
Directory.CreateDirectory() method. This statement can be issued through any script.
An approach you might consider, though, is writing a more generalized script to create
any subdirectories within your main directory. A simple example is shown below.
Create Directory
Path:
Figure 10-11. Page to create a new subdirectory.
The path and new directory name are entered into the textbox. The current path to the root
directory is precoded for appending any subdirectory structure. Remember that if the newly named
directory already exists, it is not created. Therefore, no harm comes from inadvertently clicking
the button more than one time. As you can see in the following code listing, the entered path
is checked to make sure that the new directory path is valid and is, in fact, created inside
this root directory.
<%@ Import Namespace="System.IO" %>
<SCRIPT Runat="Server">
Sub Create_Directory (Src As Object, Args As EventArgs)
Dim ValidPath As Boolean = True
Dim CheckPath As String
If Left(Path.Text, 13) = "c:\eCommerce\" Then
CheckPath = Replace(Path.Text, "c:\eCommerce\", "")
Else
ValidPath = False
Message.Text = "• Invalid path"
End If
If Len(CheckPath) = 0 Then
ValidPath = False
Message.Text = "• Missing path"
End If
Dim ValidChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_\"
Dim i As Integer
For i = 1 To Len(CheckPath)
If InStr(ValidChars, Mid(UCase(CheckPath), i, 1)) = 0 Then
Message.Text = "• Invalid character """ & Mid(CheckPath, i, 1) & _
""" in path"
ValidPath = False
Exit For
End If
Next
If ValidPath = True Then
Directory.CreateDirectory(Path.Text)
Message.Text = "• New directory <b>" & Path.Text & "</b> created"
End If
End Sub
Sub Reset_Directory (Src As Object, Args As EventArgs)
Path.Text = "c:\eCommerce\"
Message.Text = ""
End Sub
</SCRIPT>
<form Runat="Server">
<h3>Create Directory</h3>
<b>Path: </b>
<asp:TextBox id="Path" Text="c:\eCommerce\" Width="250" Runat="Server"/>
<asp:Button Text="Create" OnClick="Create_Directory" Runat="Server"/><br/>
<br/>
<asp:Label id="Message" ForeColor="#FF0000" Runat="Server"/><br/>
</form>
Listing 10-13. Code to create a directory.
In this example, the left-most 13 characters of the path string should be
"c:\eCommerce\". If this is the case, the remaining portion of the path is saved to
variable CheckPath for additional tests for a valid directory name.
The Visual Basic Replace() function removes the root path and places
the remaining characters in CheckPath.
Dim ValidPath As Boolean = True
Dim CheckPath As String
If Left(Path.Text, 13) = "c:\eCommerce\" Then
CheckPath = Replace(Path.Text, "c:\eCommerce\", "")
Else
ValidPath = False
Message.Text = "• Invalid path"
End If
If Len(CheckPath) = 0 Then
ValidPath = False
Message.Text = "• Missing path"
End If
Listing 10-14. Testing for a valid root directory.
There is also a test for a valid directory name. Here, each character in the directory name
(CheckPath) is compared with the range of valid characters stored in
string ValidChars. Note that a back-slash is included as a valid
character since the new directory may be on a subdirectory path.
Dim ValidChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_\"
Dim i As Integer
For i = 1 To Len(CheckPath)
If InStr(ValidChars, Mid(UCase(CheckPath), i, 1)) = 0 Then
Message.Text = "• Invalid character """ & Mid(CheckPath, i, 1) & _
""" in path"
ValidPath = False
Exit For
End If
Next
Listing 10-15. Testing for a valid root directory.
The valid characters are more restrictive than necessary for acceptable directory names. However,
both upper- and lower-case characters are valid since names are converted to upper-case for
comparisons.
Deleting Directories
A similar approach can be taken to delete directories. You need to be cautious, however,
since a directory, along with its subdirectories and files, can be easily deleted without any way
to recover.
Detecting Directories
Before creating or deleting a directory, a test should be made as to whether it exists. When
attempting to delete a directory, for instance, a run-time error is generated if the directory
cannot be found. The Directory.Exists() method is used to make this
determination.
Figure 10-12. General format for checking for existence of a directory.
This method returns True or False depending on
whether the supplied path, physical or relative, exists. Creating a
new directory or deleting an existing directory, then, generally follows the coding models shown
below.
If Not Directory.Exists("path") Then
Directory.CreateDirectory("path")
End If
If Directory.Exists("path") Then
Directory.Delete("path", True|False)
End If
Listing 10-16. Code to test for an existing directory and to create or delete a directory.
Moving Directories
Directories and their contents can be moved from one location to another by using the
Directory.Move() method.
Figure 10-13. General format for moving directories.
The source path is the path to a current directory; the
destination path is the path to the new target directory. Any
new directories specified in the destination path are created
if they do not exist. If the destination path already exists
then an error results. Therefore, a test for an existing path should be made when moving
directories.
With the following statements the c:\eCommerce\BookPictures
folder is moved from along side the Databases folder to inside
the Databases folder.
If Not Directory.Exists("c:\eCommerce\Databases\BookPictures") Then
Directory.Move("c:\eCommerce\BookPictures", _
"c:\eCommerce\Databases\BookPictures")
End If
Listing 10-17. Code to move a directory.
Note that the destination path includes the new
BookPictures folder that is to be created inside the
Databases folder.
Copying Directories
The Directory class does not include a
copy method to duplicate a folder structure. You can, though, create a new directory
with the same name on a different path and then copy files individually with the
File class (covered in the next tutorial).