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 (bitand) 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.
--------------------------------------------------------------------------------
note
the bit-wise and operator, bitand, is new to visual basic.net. in previous versions of visual basic and vbscript, the and operator served both as a logical and bit-wise and. for a list of new features in visual basic.net check out appendix a, "breaking cahnges in visual basic.net."
--------------------------------------------------------------------------------
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. the following discusses the 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 is 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:
listing the files in a particular directory
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.