To read the article online, visit http://www.4GuysFromRolla.com/webtech/chapters/ASPNET2/ch02.2.shtml

ASP.NET: Tips, Tutorials, and Code
Chapter 2: Common ASP.NET Code Techniques


2. Working with the File System

Very often Web application developers need to have the ability to access the file system on the Web server. Perhaps they need to list the contents of a particular text file, remove a temporary directory or file, or copy a file from one location to another.

Classic ASP provided adequate support for working with the Web server's file system. The FileSystemObject object—along with its accompanying objects such as the File, Folder, and TextStream objects—permitted the classic ASP developer to perform rudimentary tasks with the Web server's file system. One serious shortcoming of the FileSystemObject was that the developer, without having to jump through hoops, could only read and write text files; reading and writing binary files with the FileSystemObject was possible, but a pain.

The .NET Framework provides a number of classes for working with the file system. These classes are much more robust and have greater functionality than their FileSystemObject counterparts. In this section, we'll look at how to accomplish some common file system tasks:

  • Reading, creating, and deleting directories

  • Reading, writing, and creating files

Reading, Creating, and Deleting Directories

In classic ASP, developers could access directory information with the Folder object, one of the many useful FileSystemObject objects. The .NET Framework provides a plethora of file system–accessing classes in the System.IO namespace, including a DirectoryInfo class. This class will be examined in this section.

Listing 2.2.1 illustrates the DirectoryInfo class in action! From Listing2.2.1.aspx, the user can enter the name of a directory on the Web server. The page will then list the properties of that directory (if it exists), along with the directory's subdirectories. The output is shown in Figure 2.7.

Listing 2.2.1 The DirectoryInfo Class Provides Information About a Particular Directory

 1: <%@ Import Namespace="System.IO" %>
 2: <script language="VB" runat="server">
 3: Sub Page_Load(sender as Object, e as EventArgs)
 4:  If Not Page.IsPostBack then
 5:   lblDirInfo.Text = "Enter the fully qualified name of the " & _
 6:       "directory that you're interested in (<i>i.e., C:\</i>)"
 7:  Else
 8:   ' a postback, so get the directory information
 9:   Dim dirInfo as DirectoryInfo = new 
DirectoryInfo(txtDirectoryName.Text)
10:
11:   Try
12:    ' Display the directory properties
13:    lblDirInfo.Text = "<b>Information for " & txtDirectoryName.Text & _
14:     "</b><br> Attributes: " & _
15:     DisplayAttributes(dirInfo.Attributes) & "<br>Creation Time:" & _
16:     dirInfo.CreationTime.ToShortDateString() & _
17:     ", " & dirInfo.CreationTime.ToLongTimeString() & _
18:     "<br>Full Name: " & dirInfo.FullName & "<br>" & _
19:     "Root Drive: " & dirInfo.Root.Name & "<br>" & _
20:     "Parent Directory Name: " & dirInfo.Parent.Name & "<br>" & _
21:     "Directory Name: " & dirInfo.Name & "<br>Last Access Time: " & _
22:     dirInfo.LastAccessTime.ToShortDateString() & ", " & _
23:     dirInfo.LastAccessTime.ToLongTimeString() & "<br>" & _
24:     "Last Write Time: " & dirInfo.LastWriteTime.ToShortDateString() & _
25:     ", " & dirInfo.LastWriteTime.ToLongTimeString() & "<br>"
26:
27:    ' List all of the subdirectories for the current directory:
28:    lblSubDirectories.Text = "<b>Subdirectories of " & _
29:                dirInfo.FullName & "</b><br>"
30:    Dim dirSubDirectory as DirectoryInfo
31:    For Each dirSubDirectory in dirInfo.GetDirectories()
32:     lblSubDirectories.Text &= dirSubDirectory.FullName & "<br>"
33:    Next
34:   Catch dnfException as DirectoryNotFoundException
35:    ' Whoops! A directoryNotFound Exception has been raised!
36:    ' The user entered an invalid directory name!
37:    lblDirInfo.Text = "<font color=red><b>" & _
38:             dnfException.Message & "</b></font>"
39:   End Try
40:  End If
41: End Sub
42:
43:
44: Function DisplayAttributes(fsa as FileAttributes) as String
45: 'Display the file attributes
46:  Dim strOutput as String = ""
47:
48:  if (fsa And FileAttributes.Archive) > 0 Then 
 strOutput &= "Archived, "
49:  if (fsa And FileAttributes.Compressed) > 0 Then 
 strOutput &= "Compressed, "
50:  if (fsa And FileAttributes.Directory) > 0 Then 
 strOutput &= "Directory, "
51:  if (fsa And FileAttributes.Encrypted) > 0 Then 
 strOutput &= "Encrypted, "
52:  if (fsa And FileAttributes.Hidden) > 0 Then 
 strOutput &= "Hidden, "
53:  if (fsa And FileAttributes.Normal) > 0 Then 
 strOutput &= "Normal, "
54:  if (fsa And FileAttributes.NotContentIndexed) > 0 Then _
55:                      strOutput &= "Not Content Indexed, "
56:  if (fsa And FileAttributes.Offline) > 0 Then 
 strOutput &= "Offline, "
57:  if (fsa And FileAttributes.ReadOnly) > 0 Then 
 strOutput &= "Read Only, "
58:  if (fsa And FileAttributes.ReparsePoint) > 0 Then 
 strOutput &= "Reparse Point, "
59:  if (fsa And FileAttributes.SparseFile) > 0 Then 
 strOutput &= "Sparse File, "
60:  if (fsa And FileAttributes.System) > 0 Then 
 strOutput &= "System, "
61:  if (fsa And FileAttributes.Temporary) > 0 Then 
 strOutput &= "Temporary, "
62:
63:  ' whack off the trailing ", "
64:  If strOutput.Length > 0 Then
65:   DisplayAttributes = strOutput.Substring(0, strOutput.Length - 2)
66:  Else
67:   DisplayAttributes = "No attributes found..."
68:  End If
69: End Function
70: </script>
71:
72: <html>
73: <body>
74:  <form method="post" runat="server">
75:   <b>Get Information on Directory:</b><br>
76:   <asp:textbox runat="server" id="txtDirectoryName" /><p>
77:   <asp:button id="btnSubmit" runat="server" type="Submit" text="Go!" />
78:   <p><hr><p>
79:   <asp:label runat="server" id="lblDirInfo" /><p>
80:   <asp:label runat="server" id="lblSubDirectories" />
81:  </form>
82: </body>
83: </html>

Figure 2.7
Output of Listing 2.2.1 when viewed through a browser.

When working with the various file system classes, it is often handy to import the System.IO namespace to save unneeded typing (line 1).

Listing 2.2.1 uses the postback form technique we discussed in Chapter 1, "Common ASP.NET Page Techniques." On line 74, a form with the runat="server" attribute is created. In the form, there is an asp:textbox control and a submit button (btnSubmit, line 77). When a user first visits the page, Page.IsPostBack is False and lines 5 and 6 in the Page_Load event handler are executed, displaying an instructional message.

After the user enters a directory name and submits the form, the Page.IsPostBack property is set to True and the code from lines 8 through 39 is executed. On line 9, a DirectoryInfo object, dirInfo, is created. Because the DirectoryInfo class is useful for retrieving information on a particular directory, including the files and subdirectories of a particular directory, it isn't surprising that the DirectoryInfo constructor requires, as a parameter, the path of the directory with which the developer is interested in working. In this case, we are interested in the directory specified by the user in the txtDirectoryName text box.


Note

The DirectoryInfo class represents a specific directory on the Web server's file system; the DirectoryInfo constructor requires that you specify a valid directory path. However, there may be times when you don't want to have to go through the steps of creating an instance of the DirectoryInfo class just to, say, delete a directory. The .NET Framework contains a Directory class for this purpose. This class cannot be instantiated and, instead, contains a number of static methods that can be used to work with any directory. We'll examine this class later in this section.


After we've created an instance of the DirectoryInfo class, we can access its methods and properties. However, what if the user specified a directory that does not exist? Such a case would generate an unsightly runtime error. To compensate for this, we use a Try ... Catch block, nesting the calls to the DirectoryInfo classes properties and methods inside the Try block (lines 13 through 33). If the directory specified by the user doesn't exist, a DirectoryNotFoundException exception will be thrown. The Catch block starting on line 34 will then catch this exception and an error message will be displayed. Figure 2.8 shows the browser output when a user enters a nonexistent directory name.

Figure 2.8
An attractive error message is displayed if the user enters an invalid directory name.

A useful property of the DirectoryInfo class (and the FileInfo class, which we'll examine in the next section, "Reading, Writing, and Creating Files") that deserves further attention is the Attributes property. This property is of type FileAttributes, an enumeration also found in the System.IO namespace. The FileAttributes enumeration lists the various attributes a directory (or file) can have. Table 2.1 lists these attributes.

Table 2.1 Available Attributes in the FileAttributes Enumeration

Attribute

Description

Archive

Indicates the file system entity's archive status

Compressed

Indicates the file system entity's compression status

Directory

Indicates if the file system entity is a directory

Encrypted

Indicates whether the file system entity is encrypted

Hidden

Indicates if the file system entity is hidden

Normal

If the file system entity has no other attributes set, it is labeled as Normal

NotContentIndexed

-Indicates whether the file system entity will be indexed by the operating system's indexing service

Offline

Indicates if the file system entity is offline

ReadOnly

Indicates whether the file system entity is read-only

ReparsePoint

-Indicates if the file system entity contains a reparse point (a block of user-defined data)

SparseFile

Indicates if a file is defined as a sparse file

System

Indicates if the file is a system file

Temporary

Indicates whether the file system entity is temporary or not


Because each directory (or file) can have a number of attributes (such as a file being both hidden and a system file), the single Attributes property has the capability of housing multiple pieces of information. To pick out the individual attributes represented by the Attributes property, a bit-wise AND can be used (see lines 48 through 61). To properly display the attributes for a directory in Listing 2.2.1, a helper function, DisplayAttributes, is called from line 15, passing to it the FileAttributes enumeration returned by the Attributes property.

The DisplayAttributes function, spanning lines 44 through 69, returns a nicely formatted display listing the various attributes indicated by the FileAttributes enumeration passed in (fsa). On lines 48 through 61, a check is performed to determine if fsa contains a particular attribute; if it does, the textual description of the attribute is appended to strOutput, which will be returned by DisplayAttributes at the end of the function.

The DirectoryInfo class contains two useful methods for retrieving a list of a directory's subdirectories and folders. These two methods are GetDirectories(), which returns an array of DirectoryInfo objects representing the subdirectories, and GetFiles(), which returns an array of FileInfo objects representing the list of files in the directory. (We'll examine the FileInfo object in detail in the next section, "Reading, Writing, and Creating Files." In lines 31 through 33, the array returned by the GetDirectories() method is iterated using a For Each ... Next loop, displaying the subdirectories for the directory represented by dirInfo.

Listing 2.2.1 demonstrates how to list the properties of a directory (such as its attributes, creation date, last accessed date, and so on) and how to retrieve the subdirectories for a given directory. However, we have not examined how to create and delete directories.

Recall that the DirectoryInfo class represents a specific directory (after all, the DirectoryInfo constructor requires a directory path). Therefore, it makes sense that the DirectoryInfo class can only be used to create subdirectories of the physical directory represented by the DirectoryInfo instance. To create a subdirectory use the CreateSubdirectory method:

Dim dirInfo as DirectoryInfo = new DirectoryInfo("C:\Inetpub\wwwroot\")

'Create a subdirectory
dirInfo.CreateSubdirectory("images")

The preceding script creates an images subdirectory in the directory in the C:\Inetput\ wwwroot\ directory. There are a number of exceptions that the CreateSubdirectory method can throw if something goes awry.

  • ArgumentException—This exception will be thrown if you try to create a subdirectory that contains invalid directory characters (such as \, /, :, *, ?, ", <, >, and |).

  • IOException—This exception is thrown if you attempt to create a subdirectory that already exists.

  • PathTooLongException—This exception is thrown if the subdirectory you attempt to create contains too long a path. (At the time of writing this path length limitation was set at 248 characters.)

  • SecurityException—This exception occurs if the caller does not have sufficient permissions.

To delete a directory, use the DirectoryInfo class's Delete method. The Delete method will delete the directory represented by the DirectoryInfo instance. The Delete method can accept an optional Boolean parameter RecurseDirs, which if True, will delete the directory, all its files, and all its subdirectories and their files. If RecurseDir is False (or not specified at all) and you attempt to delete a directory that contains any files or subdirectories, an IOException exception will be thrown:

'Delete C:\ASP and all its subdirectories with the Delete method
Dim dirASP as New Directory("C:\ASP")
dirASP.Delete(True)

While the CreateSubdirectory and Delete methods of the DirectoryInfo class can be used to create or delete any directory on the file system, it's a bit verbose if all you want to do is quickly create a new directory. The .NET Framework provides another class, Directory, which you can use if you do not want to go through the trouble of creating an instance of the DirectoryInfo class.

The Directory class contains a number of static methods (methods that can be called without creating a new instance of the Directory class). (In fact, you cannot create an instance of the Directory method—if you try you will receive a "'System.IO.Directory.Directory()' is inaccessible due to its protection level" error.) One of these static methods of the Directory class is CreateDirectory, which, as its name suggests, creates a directory! Simply use the following syntax:

Directory.CreateDirectory(DirectoryPath)
The CreateDirectory method will throw an IOException exception if the directory DirectoryPath already exists.

To delete a directory with the Directory class, use the Delete method. The Delete method has two forms:

Directory.Delete(DirectoryPath)
Directory.Delete(DirectoryPath, RecurseDirs)

The DirectoryPath is the path of the directory that you want to delete. As with the DirectoryInfo class's Delete method, RecurseDirs is a Boolean value, which if True, will delete the directory, all its files, and all its subdirectories and their files. If RecurseDir is False (or not specified at all) and you attempt to delete a directory that contains any files or subdirectories, an IOException exception will be thrown.


Caution

When working with the file system using C#, keep in mind that the string escape sequence for C# is the backslash (\). To insert a literal backslash into a string, you must use two consecutive backslashes. For example, to delete a directory, use Directory.Delete("C:\\ASP");.


Reading, Writing, and Creating Files

Because the .NET Framework provides a class for retrieving information about a particular directory (the DirectoryInfo class), it should come as no surprise that it also provides a class for accessing file information. This class, aptly named FileInfo, contains a number of properties similar to the DirectoryInfo class. For example, the Attributes, CreationTime, Exists, FullName, LastAccessedTime, LastWriteTime, and Name properties are common to both the FileInfo and DirectoryInfo classes.

The methods of the FileInfo class are fairly straightforward; they provide the basic functionality for files. The methods to open a file are Open, OpenRead, OpenText, and OpenWrite. The methods to create a file are Create and CreateText. The methods to delete and do miscellaneous file-related tasks are CopyTo, Delete, and MoveTo.


Note

The .NET Framework also includes a File class, which is strikingly similar to the Directory class. As with the DirectoryInfo and Directory classes, the FileInfo class allows for actions on a specific file while the File class contains a number of static methods for use with any generic file.


Listing 2.2.2 illustrates how to read (and display) the contents of a text file, as well as how to use a DataList and databinding to display the contents of an array. A thorough examination of databinding and use of the DataList can be found in Chapter 7.

Listing 2.2.2 The FileInfo Class Can Be Used to Retrieve Properties or the Contents of a File on the Web Server

 1: <%@ Import Namespace="System.IO" %>
 2: <script language="VB" runat="server">
 3: Sub Page_Load(sender as Object, e as EventArgs)
 4:  If Not Page.IsPostBack then
 5:  ' What directory are we interested in?
 6:  const strDir = "C:\My Projects\ASP.NET Book\Chapter 2\Code\VB"
 7:  lblHeader.Text = "<b><u>File Listing for " & strDir & ":</u></b>"
 8:
 9:  Dim dirInfo as New DirectoryInfo(strDir)
10:  ' Get the files for the directory strDir
11:    Dim aFiles as FileInfo() = dirInfo.GetFiles ("*.aspx")
12:  dlFileList.DataSource = aFiles
13:    dlFileList.DataBind()
14:  End If
15: End Sub
16:
17: Sub dlFileList_Select(sender as Object, e as EventArgs)
18:  Dim strFilePath as String = _
19:    dlFileList.DataKeys(dlFileList.SelectedItem.ItemIndex).ToString()
20:  Dim objFile as FileInfo = new FileInfo(strFilePath)
21:  Dim objStream as StreamReader = objFile.OpenText()
22:  Dim strContents as String = objStream.ReadToEnd()
23:  objStream.Close()
24:  lblFileContents.Text = "<b>Contents of " & objFile.Name & ":</b>" & _
25:           "<xmp>" & vbCrLf & strContents & vbCrLf & "</xmp>"
26: End Sub
27: </script>
28: <html>
29: <body>
30:  <form runat="server">
31:   <asp:label id="lblHeader" runat="server" /><br>
32:   <asp:DataList runat="server" id="dlFileList"
33:          OnSelectedIndexChanged="dlFileList_Select"
34:          DataKeyField="FullName" >
35:    <ItemTemplate>
36:     <li><%# DataBinder.Eval(Container.DataItem, "Name") %><br>
37:     <font size=-1>
38:      [<asp:linkbutton Text="View Contents"
39:        CommandName="Select" runat="server"/>] |
40:      [<%# DataBinder.Eval(Container.DataItem, "Length") %> bytes]
41:     </font>
42:     <p>
43:    </ItemTemplate>
44:   </asp:DataList>
45:   <p><hr><p>
46:   <asp:label runat="server" id="lblFileContents" />
47: <form>
48: <body>
49: <html>

The code in Listing 2.2.2 serves a very simple purpose: to list the ASP.NET pages in a particular directory and to allow the user to view the source code for any one of these pages. This can be thought of as two separate tasks:

  1. Listing the files in a particular directory

  2. Displaying the contents of the selected file

The first task is handled by the Page_Load event handler (lines 3 through 15) and the DataList control (lines 32 through 44). The first line of the Page_Load event handler checks to determine if the page is being visited for the first time (if so, Page.IsPostBack will be False, and the code from lines 5 through 13 will be executed). In such a case, we want to display the files for a particular directory. On line 6, the directory path whose files will be displayed has been hard coded and stored in the constant strDir. By using concepts from Listing 2.2.1, however, Listing 2.2.2 could be expanded to allow the user to specify the directory.

Next, those files in the directory strDir that end with the .aspx extension are returned (line 11). The GetFiles method of the DirectoryInfo class can accept an optional parameter indicating that only a subset of files should be returned from the directory. This optional parameter, if specified, is a search criteria field in which wildcards can be used to limit the files returned. Because we are only interested in listing ASP.NET pages, we want to grab only those files that have the .aspx extension. The GetFiles method returns an array of FileInfo objects, which we assign to our variable aFiles (line 11).

On lines 12 and 13, we bind this array to dlFileList, our DataList whose definition begins on line 36. The DataList uses databinding syntax to display the Name property of each FileInfo object in the aFiles array (line 36) along with the Length property, which indicates the file's size in bytes (line 40). In the DataList heading (lines 32 through 34), the SelectedIndexChanged event is wired up to the dlFileList_Select event handler; furthermore, the DataList specifies the FullName property of the FileInfo class as its DataKeyField (line 34).

A LinkButton server control is created on lines 38 and 39 with a CommandName of Select. When this LinkButton is clicked, the page will be reposted and the dlFileList_Select event handler will be called. From the dlFileList_Select event handler, the FullName of the file clicked can be programmatically determined because of the DataKeyField property on line 34. If you are unfamiliar with the DataList control and databinding, this might be a bit overwhelming to you. Don't worry, though; databinding will be discussed thoroughly in Chapter 7.

After a View Contents link is clicked, the page will be reloaded and we're on to the second task: displaying the contents of the selected file. This is handled in the dlFileList_Select event handler. On line 19, the clicked LinkButton's DataKeyField is extracted and stored in the variable strFilePath. This contains the full path to the file that we want to display.

Next, on line 20, a FileInfo object is instantiated and the constructor is called, passing it the path of the file we are interested in. To simply read the contents of a text file, the FileInfo class provides an OpenText method, which returns a StreamReader instance that can be used to step through the contents of the file. On line 21, a StreamReader instance is created and assigned to the object returned by the OpenText method. Next, the entire stream is read into a string variable, strContents (line 22), and the stream is closed (line 23).

On line 24 and 25, the contents of the selected file are displayed in the lblFileContents label server control. Because we are displaying the contents of a file that likely contains HTML and script-block code, the contents are surrounded by a pair of XMP tags. (The XMP tag is a standard HTML tag that displays text ignoring all HTML tags.)

Figure 2.9 shows the output of the code in Listing 2.2.2 when we first visit the page. Note that the contents of the specified directory are displayed with a link to view the source and a note on their file size.

Figure 2.9
When the user first visits the page, she is shown a listing of files.

When the user clicks the View Contents link for a particular file, the page is reloaded and the file's contents are displayed beneath the file listing. Figure 2.10 shows what a user would see after clicking on a particular file in the listing.

Figure 2.10
Clicking on a particular file displays its contents beneath the file listing.

In Listing 2.2.2 we examined how to list the contents of a directory, how to list certain FileInfo class properties, and how to read the contents of a text file. However, we've yet to look at how to create a file and how to work with binary files (a task that was difficult in classic ASP with the FileSystemObject).

Creating Text Files

Let's first examine how to create a file. Listing 2.2.3 demonstrates an ASP.NET page that serves as a very basic Create your own Web Page utility. From the page, users can enter a filename for their HTML page and the HTML code; when they click the Create HTML Page button, a new HTML page will be created on the server with the HTML syntax they entered. After this file is created, anyone can view it via his or her browser.

The script in Listing 2.2.3 demonstrates the functionality of an extremely simple HTML file editor that might be found on a site that allows users to create personal home pages. Listing 2.2.3 is written in C#; note some of the similarities and differences between C#'s syntax and VB's syntax. For example, to insert a literal backslash into a string, when using C# you must use two consecutive backslashes (line 6). The output is shown in Figure 2.11.

Listing 2.2.3 The File and StreamWriter Classes Allow Developers to Create Files on the Web Server

 1: <%@ Import Namespace="System.IO" %>
 2: <script language="C#" runat="server">
 3:  void btnSubmit_OnClick(Object sender, EventArgs e)
 4:  {
 5:   // Create an HTML file in the directory strDir
 6:   const String strDir = "C:\\Inetpub\\wwwroot\\UserPages\\";
 7:
 8:   String strFileName = strDir + txtPageName.Text;
 9:
10:   // Create the file using the static method CreateText
11:   StreamWriter objStream = File.CreateText(strFileName);
12:
13:   // Write the contents of the txtContents textarea to the stream
14:   objStream.Write(txtContents.Text);
15:
16:   // Close the stream, saving the file...
17:   objStream.Close();
18:
19:   // Display a link to the newly created HTML page.
20:   lblLink.Text = "Page created!<br><a href=\"/UserPages/" +
21:          txtPageName.Text + "\">View New Page!</a>";
22:  }
23: </script>
24:
25: <html>
26: <body>
27:  <form runat="server">
28:   <font size=+2><b>Create your own HTML page!</b></font>
29:   <p>
30:   <b>Name:</b> <asp:textbox id="txtPageName" runat="server" /><br>
31:   <b>Contents:</b><br>
32:   <asp:textbox id="txtContents" runat="server" TextMode="MultiLine"
33:         Columns="40" Rows="5" />
34:   <p>
35:   <asp:button id="btnSubmit" runat="server" text="Create HTML Page!"
36:         OnClick="btnSubmit_OnClick" />
37:   <p>
38:   <asp:label id="lblLink" runat="server" />
39:  </form>
40: </body>
41: </html>

Figure 2.11
The user can enter HTML and a filename and the ASP.NET page will generate a file on the Web server with the proper name and contents!

Listing 2.2.3 is the first code sample we've looked at in this chapter that did not include the Page_Load event handler. Therefore, before looking at the C# code, let's turn our attention to the HTML portion first (lines 25 through 41). First, note that we are using postback forms, so we must create a form with the runat="server" attribute (line 27). Next, we need two text boxes: one for the user to enter the filename of the HTML page he wants to create and another for the HTML contents for the page.

The text box for the filename, txtPageName, is created on line 30. The text box for the HTML contents, txtContents, is created as a multiline text box with 40 columns and 5 rows (lines 32 and 33). A multiline text box is, in HTML terms, a TEXTAREA. Next, we create a button and wire up its click event to the btnSubmit_OnClick event handler (lines 35 and 36). The last server control is a label, lblLink, which we'll use to display a link to the newly created HTML page.

When the Create HTML Page! button is clicked, the postback form is submitted and the btnSubmit_OnClick event handler is called. This event handler's task is to create the file specified by the user with the HTML contents specified by the user. All the HTML files created by the user will be placed in the directory specified by the string constant strDir (line 6). The actual filename for the file to be created is the concatenation of strDir and the value the user entered in the txtPageName text box (line 8).

On line 11 the static version of the CreateText method is used to create a new text file. The static version of the CreateText method expects a single parameter, the path to the file to create, and returns a StreamWriter object that can be used to write the contents to the newly created file. On line 14, the Write method of the StreamWriter class is used to write the HTML contents entered by the user to the file. This file is saved on line 17, when the Close method is called. Finally, a link to the newly created file is displayed on lines 20 and 21.


Caution

The code in Listing 2.2.3 does not contain any sort of error-handling code. If the user doesn't enter a filename, an exception will be thrown. Additionally, if the C:\Inetpub\wwwroot\UserPages\ directory does not exist an exception will be thrown. Either of these errors could be remedied via a try ... catch block, an if statement in btnSubmit_OnClick to check if txtPageName contains a valid value, or through a validation control. (For more information on try ... catch blocks, be sure to read Chapter 9, "ASP.NET Error Handling." For information on validation controls, refer to Chapter 3, "Form Field Input Validation.")


Working with Binary Files

The FileSystemObject objects used with classic ASP were designed to work with text files. The file system objects in the .NET Framework, however, were designed to be much more flexible, able to easily work with binary or text files alike. So far, we've examined how to read and create text files. It's time that we took a quick look at how binary files are handled.

The code in Listing 2.2.4 uses the static version of the Open method of the File class to open a binary file (in this case, a GIF file). The binary data is then squirted to the user's browser via the Response.BinaryWrite method. Because browsers can inherently display GIF files, the user ends up seeing the image file as though he had directed his browser directly to the image file on the Web server (as opposed to an ASP.NET page).

Listing 2.2.4 The .NET Framework Can Easily Handle Both Binary and Text Files

 1: <%@ Page ContentType="image/gif" %>
 2: <%@ Import Namespace="System.IO" %>
 3: <script language="vb" runat="server">
 4:  Sub Page_Load(sender as Object, e as EventArgs)
 5:   Const strFileName as String = "C:\Inetpub\wwwroot\Web.gif"
 6: 
 7:   ' Read the contents of a binary file
 8:   Dim objStream as Stream = File.Open(strFileName, FileMode.Open)
 9: 
10:   Dim buffer(objStream.Length) as Byte
11:   objStream.Read(buffer, 0, objStream.Length)
12:   objStream.Close()
13: 
14:   Response.BinaryWrite(buffer)
15:  End Sub
16: </script>

Listing 2.2.4 displays a GIF in the users browser specified by the hard-coded file path on line 5. Next, on line 8, the Open method is used to retrieve a Stream object to the GIF file's contents. There are many variations of the Open method; in this example we pass the Open method two parameters: the path to the file to open and the FileMode access to use. FileMode is an enumeration with its various entries representing various modes of which a file can be accessed. Table 2.2 lists these various file modes.

Table 2.2 The FileMode Enumeration Contains the Various Modes through which a File Can Be Accessed

Attribute

Description

Append

If the files exists, it is opened and the stream is positioned at the end of the file; if the file does not exist, it is created.

Create

Creates a new file if the file does not exist; if the file does exist, it is overwritten.

CreateNew

Specifies that a new file should be created.

Open

Opens an existing file.

OpenOrCreate

Specifies that the file should be opened if it exists, and created if it does not currently exist.

Truncate

Opens an existing file and positions the stream at the beginning of the file to overwrite existing data.


The Open method returns a Stream object that we can use to read from the file. The Stream class contains a Read method that takes three parameters: a buffer as a byte array, an integral offset, and an integral count, in the following format:

Stream.Read(buffer(), offset, count)

The Read method will then dump count bytes from the stream into the buffer array starting at a specified offset in the array. Before we execute this statement, though, we need to create and initialize a buffer array. Because we want to read the entire contents of the GIF file into our array, we need to create an array the size of the GIF file. This size can be retrieved from the Length property of the Stream class (line 10).

When we have this array properly initialized, we can go ahead and dump all the contents of the GIF file into the buffer using the Read method (line 11). Note that we are beginning the dump into the start of the buffer (hence offset is set to zero) and we are reading the entire stream (hence count is set to the length of the stream—objStream.Length).

Finally, the byte array is squirted to the browser using the BinaryWrite method of the Response object. The code in Listing 2.2.4, when viewed through a browser, will display the GIF specified by strFileName (line 5). Figure 2.12 is a screenshot of the browser visiting Listing2.2.4.aspx.

Figure 2.12
Use the Stream object to read binary files.


Note

Note that on line 1 of Listing 2.2.4 we used the page-level directive ContentType, setting it to image/gif. This ContentType setting is sent along as an HTTP header to the browser, indicating the type of binary content being sent. Note that we could have experienced the same results by inserting the following line before line 14 in Listing 2.2.4:

Response.ContentType = "image/gif"


  • Read Part 3


  • Article Information
    Article Title: Common ASP.NET Code Techniques
    Article Author: Scott Mitchell
    Published Date: Friday, September 28, 2001
    Article URL: http://www.4GuysFromRolla.com/webtech/chapters/ASPNET2/ch02.2.shtml


    Copyright 2017 QuinStreet Inc. All Rights Reserved.
    Legal Notices, Licensing, Permissions, Privacy Policy.
    Advertise | Newsletters | E-mail Offers