NOTE:
The computer file system that we'll be manipulating is
the web server's. So make sure you have the appropriate
privileges and information (i.e., so you don't upset your
ISP). Ideally, you'll have a web server set up on your own
computer so you can test and play. If you're running on the
Windows platform and don't have a server set up,
try Microsoft's free Personal Web Server.
FSO Model Objects
Drive Object
Provides access to a disk or
network drive
FileSystemObject Object
Provides access to a computer's file
system
Folder Object
Provides access to all properties of a
folder
TextStream Object
Provides an easy way to access a file's
contents
You can use the above objects to do nearly anything on a computer,
including wreak havoc - so be careful how you play with the FSO.
In a web environment, it can be very important to store information,
such as user info, log files, etc. The FSO provides a powerful
and easy way to store your data in an efficient manner. In this
article,
we'll be mainly concentrating on the FileSystemObject
and TextStream Objects.
NOTE:
The FSO is provided by Microsoft, and as such, the results
for its use on non-Microsoft operating systems are questionable
in the least. For non Windows OSes, you probably wouldn't
be using active server pages anyway, but I still wouldn't
recommend trying the FSO.
How Do I Use the FSO?
To be able to use the FSO to perform all your dirty work, you must
first create the object. If you're familiar with creating objects
in ASP pages, then this next line should be no surprise:
<%
Set fso = Server.CreateObject("Scripting.FileSystemObject")
%>
We create the FSO here and set the reference to the variable fso.
We can now use the familiar object.method syntax to perform
file system
manipulations. (Check out the
Visual Basic documentation
to learn more about objects and object
oriented programming.) In this case, we can use fso.method
or fso.
property, as we'll see in upcoming examples.
NOTE:
The FSO model is located in the scripting runtime dll
provided by Microsoft, scrrun.dll. You can reference this dll
in any application that can reference objects, such as
MS Access, Word, and a whole slew of others. This means
you're not restricted to just using the FSO in an ASP page.
Here is an abridged list of methods available to the
FSO that we will use here to manipulate files:
File Methods
CopyFile
Copies one or more files from one
place to another
CreateTextFile
Creates a file and returns a TextStream
object
DeleteFile
Deletes a file
OpenTextFile
Opens a file and returns a TextStream
object that can be used to read from or append to the file
For a complete list of all the methods and properties of the FSO,
check out
the Microsoft MSDN reference. Let's move onto some examples.
Writing Files
Suppose you wanted to create a simple guestbook. You could set up a
database and store
users' information there.
However, if you don't
need the power of a database application, you can save yourself some
money and overhead, and use the FSO to store your information. Not to
mention the fact that your ISP may limit your choice of database
options.
Let's assume you'll collect some user information in a form.
(Check out
WDVL's primer on forms.) Here's the HTML for a simple
form:
Let's look at the script in formhandler.asp that will handle
the form:
<%
' Get form info
strName = Request.Form("username")
strHomePage = Request.Form("homepage")
strEmail = Request.Form("Email")
' create the fso object
Set fso = Server.CreateObject("Scripting.FileSystemObject")
So far, this should be nothing new. We take the form variables and
assign them to variables for easier use later on. Now comes the fun
part - writing the file:
path = "c:\temp\test.txt"
ForReading = 1, ForWriting = 2, ForAppending = 8
' open the file
set file = fso.opentextfile(path, ForAppending, TRUE)
' write the info to the file
file.write(strName) & vbcrlf
file.write(strHomePage) & vbcrlf
file.write(strEmail) & vbcrlf
' close and clean up
file.close
set file = nothing
set fso = nothing
As you recall, the OpenTextFile method returns a TextStream object,
which is another object of the FSO model. The TextStream object
exposes
methods
to manipulate a file's content, such as
Write, ReadLine, and SkipLine. The VB constant vbcrlf generates
a line break.
NOTE:
We specify TRUE in the argument list of OpentextFile to
tell the system to create the file if it doesn't already
exist. If the file does not exist, and you do not specify
TRUE, you will generate an ugly error.
Now navigate to c:\temp and open test.txt. You should see the following
information:
User's name
User's home page
User's email
Of course those words will be replaced by whatever the user entered
in the form. Now anyone can come along and fill out your guestbook
and their information will be stored in this file.
Reading Files
So now we have some nice user information stored in a file, which
happily works as a simple database. Now suppose a user comes along
and wants to view all your wonderful visitors. We've got to
spit that
information out somehow. Since we don't have a database with
nicely structured columns, we'll have to get clever to output
the results we want.
We know that in the file we just created, the first line is the
user's
name, the second line is their homepage, and the third line is their
email address. Every subsequent user who comes along will also have
their information stored in this way, so that every third line will
contain the same type of information. Knowing that, we can now write
some code to grab the info:
<%
' create the fso object
set fso = Server.Createobject("Scripting.FileSystemObject")
path = "c:\temp\test.txt"
' open the file
set file = fso.opentextfile(path, 1) <-- For
reading
Now let's grab each line and format it accordingly:
do until file.AtEndOfStream
Response.write("Name: " & file.ReadLine & " ")
Response.write("Home Page: " & file.ReadLine & " ")
Response.write("Email: " & file.ReadLine & "<p>")
loop
' close and clean up
file.close
set file = nothing
set fso = nothing
%>
NOTE:
We did a very simple output here, but note that you can
place the information wherever and however you like, including
in table cells and
DHTML forms.
If you've created and written your file properly, this little loop
will properly list everyone in your database. The ReadLine method reads
one line up to the newline character. Subsequent calls to ReadLine
will read the next lines. AtEndOfStream is a property of the
TextStream
object that lets
us know when we've hit the end of the file.
Suppose for some reason we didn't format the file correctly. If a
user only has 2 lines instead of 3 describing their info, then we
will get some errors here. Our loop gets the next 3 lines
in the file and if there are not 3 more lines to be had, your page
will get mad and throw an error like:
Server object error 'ASP 0177 : 800a003e'
at you. So be sure to add some error
checking to make sure you're not skipping or inserting too many
lines.
Permissions
Now that we've covered the basics, we should discuss permissions.
The FSO runs in the user account that created it. In other words,
if someone accesses your page from the internet, then the internet
account created the FSO. If you are logged onto your computer as
the administrator and you access the page, then the administrator
account created it. This is very
important, because certain accounts have certain permissions, and
the FSO requires a lot of permissions in order to function fully.
The internet account (IUSER_MachineName, where MachineName is the name
of the server) generally has only reading privileges. That means
that users will never be able to write to the guestbook file. There
are,
however, several options to skirt around this issue.
The first, and more difficult, would be to require the user to log
on to the server before they fill out the guestbook. However, the
point of a guestbook is to get information from anonymous users, and
to log users on, we'd have to know who they are, so
we'll skip this option and move on.
The second is to create a directory or file that allows the
IUSER_MachineName
account writing privileges. This can open up some potential
security holes,
because anyone who knows the proper directory and some savvy web skills
can write stuff to your server. This is a big no-no. So you want to
make
sure you place the writeable directory in a nice and hidden spot,
and possibly
place it outside of the web directory structure (i.e. in Windows,
place it in a
directory that is outside the inetpub directory)
Searching with the FSO
You may be thinking "Great, so now I know how to write files. I
could've
figured that out myself." So you want more tough guy? Let's
try building a
search feature for your web site.
The key to building a search engine is recursion. If you don't
know
what recursion is, find out
why it's cool.
Basically, you write one piece of code that performs a search on
the files in a directory, and then make that same code loop through
all the subdirectories. Since we don't know ahead of time how many
subdirectories there may be, we have to call this piece of code over
and over again until we're through. Recursion in it's
finest.
So let's build the search page. We'll assume that
you've already
built an HTML form for a user to input a search string.
Dim objFolder
Dim strSearchText
Dim objFSO
strSearchText = Request.Form("SearchText") <-- The
search string
' create the FSO and Folder objects
Set fso = Server.CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(Server.MapPath("/"))
Search objFolder
The above code simple initializes variables and gets us started.
The meat of the search is performed by the Search function,
described below:
Function Search(objFolder)
Dim objSubFolder
'loop through every file in the current
folder
For Each objFile in objFolder.Files
Set objTextStream = objFSO.OpenTextFile(objFile.Path,1) <-- For Reading
'read the file's contents into a
variable
strFileContents = objTextStream.ReadAll
'if the search string is in the file, then
write a link
' to the file
If InStr(1, strFileContents, strSearchText, 1) then
Response.Write "<A HREF=""/" & objFile.Name & _
""">" & objFile.Name & "</A><BR>"
bolFileFound = True
End If
objTextStream.Close
Next
'Here's the recursion part - for each
' subfolder in this directory, run the Search function again
For Each objSubFolder in objFolder.SubFolders
Search objSubFolder
Next
End Function
NOTE:
To be able to open files, the FSO requires the actual
path to the file, not the web path. For instance,
c:\inetpub\wwwroot\temp\index.html,
not www.enfused.com/temp/index.html or /temp/index.html. To
convert
the latter to the former, we use Server.MapPath("filename"),
where filename represents the web path.
The code above will run through every subdirectory of every folder
under the initial folder that you specified, which in this case,
would be the root web path, specified by "/". Then we simply open
each file in the directory, see if the desired string is in that file
and display a link to that file if the search string is found. Not
bad, huh?
Note that as the number of files and subdirectories increases,
so will the time it takes to run this search. It's recommended
that
if you need a heavy duty search feature, turn to something else,
such as Microsoft's Index Server.
Content Management with the FSO
By now, you should have a good taste of the FSO and its methods and
properties. Let's dig a little deeper and do some engineering
design to
tackle a more difficult problem.
Content management is being able to keep track of, manipulate, and
generally perform tasks with content, typically documents in a web
environment. Smart content management does all that in an easy,
painless
fashion. (Check out
this
article
to study up on content management.) Behind the scenes
of such an application is heavy duty file manipulation. Once again,
enter the FSO. We need to be able to move, delete, rename, and create
files, and our friend the FSO steps in nicely. In the article
above, we
discuss a submission system for writers to
publish their content. What we don't mention is exactly what
to do with
the file once it's up.
First of all, you'll most likely want to rename the file,
since the writer
probably named it something only he would understand or care about.
To be able to keep track of all your documents, you'll want to
rename it
to something unique, that is easily identifiable by your system.
Unfortunately,
the FSO doesn't allow for an easy file renaming, so we'll
have to engineer
a bit.
<%
' create the fso object
set fso = Server.Createobject("Scripting.FileSystemObject")
path = "c:\temp\test.txt"
strDate = Replace(Date(), "/", "")
strDir = "c:\inetpub\wwwroot\articles\" & strDate
strNewFileName = Hour(Now) & "_" & Minute(Now) & "_" &
second(Now) & ".html"
' open the old file
set file = fso.opentextfile(path, 1) <-- For
reading
strText = file.readall
set file = nothing
' check for and/or create folder
if not fso.folderexists(Server.MapPath(strDir)) then
set f = fso.CreateFolder(Server.MapPath(strDir))
else
set f = fso.GetFolder(Server.MapPath(strDir))
end if
' create and write new file
set file = fso.Createtextfile(f.path & "\" & strNewFileName)
file.write(strText)
set f = nothing
file.close
set file = nothing
' delete the old file
fso.DeleteFile(path & "\" & rst("FileName") & i)
' clean up
set fso = nothing
%>
The lack of the FSO's abilities however can be used to our
advantage here;
we can perform two steps in one. First, we open and read the
file's contents.
I'll assume that we'll want to create a unique folder, as
well as a unique
filename to store the article in. However, since this folder's
path will
change every day, we'll have to first check to see if the folder
already exists, and if it doesn't, create it. This is done by the
if not fso.folderexists section. We then get that path
and use
it to create the new file (you'll recall that the FSO needs
the full path
name to manipulate files, and the GetFolder and
CreateFolder
methods return just that - a full path). After we're done with
the new file,
we'll want to get rid of the old one,
so it doesn't clutter up our file system. This is accomplished
with
fso.DeleteFile.
So the two steps we accomplished here were renaming the file, and
moving
it to a more apropos directory. Note that we could also have done some
more manipulation here, such as editing the text before we wrote it to
the new file.
What You Can't Do
The FSO does have some weaknesses - for instance, it stumbles on
binary files. This includes MS Word documents, many image formats,
and, unfortunately, a lot of other files. You can still, however
otherwise manipulate these files - move them, delete them, etc. What
you can't do is open, read, or write to them. Given some
ingenuity,
a method could be devised to use the FSO to play with binary files,
but many will find it easier to simply use the old Open method
(check out
MSDN for an example).
Another limitation is file size. When you read or write a lot of
content at once, all the information is stored in memory - and the
larger your content, the larger the memory usage. This tends to slow
everything down, so if you need to manipulate really large files,
or a ton of smaller files, consider breaking the files down into
smaller pieces and clearing the memory often (setting your variables
equal to NULL or "", and releasing your objects ASAP). Moving your
application into a COM object would also tremendously speed up the
process.
You also can't manage permissions and file and folder attributes
with the FSO. A great way to implement security would be to create
the guestbook file we described earlier as read-only, and then change
the attribute to writeable only when we need it, and immediately
change it back. This method is often used in
CGI and
Perl
scripts,
but unfortunately, there's no pleasant way to do this with the
FSO.
What else can I do?
There are a lot of really cool features in the FSO model that most
people
aren't aware of. These are the type of features that you
normally find
out about after you did things the hard way, and you end up
saying "If only I knew that before!"
I'll briefly list the not-so-common but cool functions here.
Little Known FSO Features
GetSpecialFolder Method
Returns the path to a special
Windows folder: the Windows installation folder; the system folder;
and the Windows Temporary folder. Syntax: FSO.GetSpecialFolder([0,
1, or 2])
GetTempName Method
Returns a randomly generated temporary
file or folder name. Useful when you need to store temporary
data (i.e. when you run into the file size limitation described
above).
GetAbsolutePathName Method
Returns the absolute path of a folder (similar
to Server.MapPath). For example, FSO.GetAbsolutePathName("region") will
return something like "c:\mydocs\myfolder\region"
GetExtensionName Method
Returns the extension for the last item
in a path (i.e. FSO.GetExtensionName("c:\docs\test.txt") will
return txt)
GetBaseName and GetParentFolder Methods
Returns the base and parent folder name
respectively of last item in a path (i.e. FSO.GetParentFolder
("c:\docs\mydocs")
will return 'docs')
Drives Property
Returns a collection of all the drive
objects available on the local machine. This is helpful if you
ever want to build an explorer type interface.
You'll want to make sure you build in robust error handling
routines
though, because some of these above functions will return nasty
errors if the specified file or folder does not exist.
Conclusion
As we can see, the FSO is very nifty, and we only touched the tip
of the 'berg here. Many of these features
are implemented on sites such as
Enfused and other big-name sites, and
many of them pay big bucks for applications that can do this
type of thing. Meanwhile the little 'ol FSO sits by and waits
for someone to come across and use his power! Um..whoops, did I
say that aloud?
The takeaway here is that you can build very powerful applications
with
the FSO, as well as accomplish some simples tasks more easily. Keep
this one in your
toolbelt!
Happy scripting!
About the Author
Chris Payne Currently lives in the Boston area. He has been building
database driven web sites for
several years. In February 2000, he cofounded Enfused Media, Inc, a web
development/gaming firm.
The first development from EMI was www.enfused.com, a massive gaming portal
for gamers as well
as the gaming business. His offline time is spent with his fiance and
their tropical fish.
Email: clpayne@enfused.com
Built around the Microsoft CryptoAPI, AspEncrypt helps you harness all major encryption and hashing algorithms such as DES, Triple-DES, RC2, RC4, RSA, MD5 and SHA1 in just a few lines of code. The component can be used in tandem with AspEmail to send encrypted and signed mail in the industry-standard S/MIME format, or with AspUpload to encrypt files as they are being uploaded. AspEncrypt can also be used to issue and manage X.509 digital certificates.
AspPDF is an ASP/ASP.NET component which enables generation and management of documents in PDF format. Features include advanced text formatting, font embedding, form fill-in, images, tables, content and page extraction, document stitching, encryption, digital signatures, and more.
In many web applications it is desirable for both intranet users and external parties to be able to seamlessly log onto the system. The problem this raises is that it is not easy to allow intranet users to log in via Windows integrated authentication while also allowing external parties to log in to the same application using standard forms authentication. This article will show you one way to achieve the best of both worlds when it comes to authentication. [Read This Article][Top]
In this article, Michele Leroux Bustamante discusses authentication, authorization and role-based security in .NET. Along the way, he provides some best practices for implementing role-based security in some typical .NET application scenarios including rich clients, Web applications, and Web services. [Read This Article][Top]
When implementing custom components that require access to restricted resources, implicit impersonation must be used. Jay Nathan shows how to create a class that makes using .NET Impersonation a snap. [Read This Article][Top]
Learn about the execution process of CLR-based programs and how to protect your applications from being easily disassembled back into source code. [Read This Article][Top]
Businesses that utilize encrypted e-mail may find Secure Multipurpose Internet Mail Extensions (S/MIME) to be somewhat restrictive. This article shows how to use security features in PDF as an alternative to S/MIME. [Read This Article][Top]
Bill Gates, in a recent interview, predicted the end of spam by 2006. One of the methods he mentioned involved a challenge only a real live person could handle. Adnan Masood shows how to use AI and .NET to create a user verification scheme that incorporates similar concepts Gates alluded to.
[Read This Article][Top]
Code Access Security (CAS) is the .NET Framework security model that grants
code permission to resources based on "evidence" pertaining to the
encapsulating assembly. In this article, David Myers examines CAS
and explains different configuration methods. [Read This Article][Top]
Zhenlei Cai combines an open source C++ encryption library with SQL Server
extended stored procedures to create a platform neutral, transparent
encryption solution that resides at the database layer. [Read This Article][Top]
Christopher Spann offers a .NET configuration tip that should help ease system administrators' fears of security compromise and thus assuage growing developer demand for a .NET environment. [Read This Article][Top]
You don't have to be a cryptography expert or spend lots of money on third-party components to secure sensitive data in .NET. In this article, Wayne Plourde shows just how easy it is to encrypt cookie data using encryption classes in the .NET System.Security.Cryptography namespace. [Read This Article][Top]
Mailing List
Want to receive email when the next article is published? Just Click Here to sign up.