奇妙的文件系统对象组件

---摘自《ChinaAsp网络》(文/讨饭猫)
注意:我们在下文中要操作的是Web服务器的文件系统，所以首先要确定你对该服务器有足够的权限。如果你不想麻烦你的Web Master，你也可以用微软的Personal Web Server来进行你的试验。
FSO对象包括
驱动器对象（Drive Object）用来存取本地盘或网络盘，
文件系统对象（FielSystemObject 简称FSO）是用来存取文件系统
文件夹对象（Folder Object）用于存取文件夹的各种属性
文本流对象（TextStream Object 简称TS）存取文件内容
使用以上对象，你的确可以在一台电脑上为所欲为，但同样也可能会造成灾难，所以在使用FSO的时候要注意安全，特别是在Web应用中，Web服务器中会存储诸如用户信息，日志文件等等重要信息，更要格外小心。在本文中，我们主要探讨FSO对象和TextStream对象
（FSO由Microsoft提供，所以本文内容只适用于Windows操作系统下的ASP编程。）
如何使用FSO？
要开始干坏事之前，首先要学会建立FSO。如果你曾经在ASP中创建过对象，那么这事好办：
<%
Set fso = Server.CreateObject("Scripting.FileSystemObject")
%>
现在我们已经建立了FSO，并赋值给变量fso，接下来就可以使用我们熟悉的object.method方法来使用它了（如果你对对象的操作不熟悉，请自己去补课，这里恕不奉陪）。在下面的例子中，主要使用的是fso.method和fso.property。
（FSO模块来自微软提供的脚本运行库scrrun.dll中，许多应用系统都会调用它，例如Access,Word等等，并非专为ASP应用开发。）
下面是我们要用到的部分FSO方法：
CopyFile 拷贝一个或多个文件
CreateTextFile 创建一个文件并返回一个TS对象
DeleteFile 删除一个文件
OpenTextFile 打开一个文件并返回一个可用于读和添加的TS对象。
要获得完整的FSO方法，请参看MSDN。下面看个例子吧。
写文件
设想你要建立一个简单的guestbook，而又不想用复杂的数据库，或者你的ISP限制你用数据库，大可以用FSO来干。
假设你要从用户提交的form中收集信息，html这样写.
<html>
<body>
<form action="formhandler.asp" method="post">
<input type="text" size="10" name="username">
<input type="text" size="10" name="homepage">
<input type="text" size="10" name="Email">
</form>
</body>
</html>
再看看用于处理这个form的formhandler.asp。
<%
' 获取 form信息
strName = Request.Form("username")
strHomePage = Request.Form("homepage")
strEmail = Request.Form("Email")
' 建立fso对象
Set fso = Server.CreateObject("Scripting.FileSystemObject")
path = "c:\temp\test.txt"
ForReading = 1, ForWriting = 2, ForAppending = 3
' 打开文件
set file = fso.opentextfile(path, ForAppending, TRUE)
' 把信息写入文件
file.write(strName) & vbcrlf
file.write(strHomePage) & vbcrlf
file.write(strEmail) & vbcrlf
' 关闭并清除对象
file.close
set file = nothing
set fso = nothing
看看上面，OpenTextFile方法返回了一个TS对象，TS对象提供了例如Write,ReadLine,SkipLine等一系列的方法来操作文件内容。VB常量vbcrlf是换行符。
（我们在OpentextFile方法中指定了TRUE参数，通知系统当文件不存在时生成一个新文件。如果不用TRUE，当文件不存在时就会返回一个难看的错误提示。）
现在打开c:\temp\test.txt，你可以看到如下信息：
User's name
User's home page
User's email
当然，实际内容是用户的输入。哈，一个简单的guestbook诞生啦。
读文件
好，现在我们的guestbook里已经存储了不少用户的信息了，如果这时一个用户想看看我们访客的信息，我们得把信息再还原出来。由于不是数据库，得自己动手来解决分段问题。看看test.txt,每三行就是一个用户的信息，好办：
<%
' 建立fso对象
set fso = Server.Createobject("Scripting.FileSystemObject")
path = "c:\temp\test.txt"
'打开文件
set file = fso.opentextfile(path, 1) <-- 用于读
do until file.AtEndOfStream
Response.write("Name: " & file.ReadLine & " ")
Response.write("Home Page: " & file.ReadLine & " ")
Response.write("Email: " & file.ReadLine & "<p>")
loop
' 关闭并清除
file.close
set file = nothing
set fso = nothing
%>
（这里我们只是将信息简单输出，你可以根据实际情况作调整，包括输出到表格和DHTML form中。）
ReadLine方法用于从文件中读取一行，下次调用ReadLine方法将读取下一行。AtEndOfStream是TS对象的一个属性，让你知道是否到达文件结尾。
假设由于某种原因文件有问题，例如某个用户只有两行，那么我们会得到以下错误信息：
Server object error 'ASP 0177 : 800a003e'
所以加入一些错误处理代码是必要的。
FSO的权限问题
现在我们已经对FSO有一些基本认识了，是时候来讨论一下FSO的权限问题。FSO的读取权限就是创建FSO的账号所拥有的权限。如果某人从Internet上使用这个页面，那么创建FSO的就是Internet账号。如果你用administrator本机登录并访问页面，那么建立的FSO就拥有administrator的权限。
Internet账号（IUSER_机器名）通常只有读权限，这意味着用户永远无法写guestbook文件。所以必须想办法解决。
第一个办法，是让用户首先要用一个有写权限的账号登录。但实际上所有从Internet访问的用户都是以anonymous登录，所以这个方法比较难实现。
第二个方法是建立一个允许账号为 IUSER_机器名 的用户读写的目录。但这样可能会带来安全漏洞。如果这个目录让黑客知道了，就可以往里面写一些代码并通过某种方式运行它，那你就惨了。所以最好将这个目录建立在Web路径之外（也就是inetpub路径之外）。
用FSO实现search功能
现在让我们来做更进一步的工作，用FSO在我们的Web站点上实现search功能。建立搜索引擎的关键是递归。
首先来建立搜索页面。假设我们已经给用户提供了一个输入搜索字符串的页面。
Dim objFolder
Dim strSearchText
Dim objFSO
strSearchText = Request.Form("SearchText") <-- 搜索字符串
' 建立 FSO 和文件夹对象
Set fso = Server.CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(Server.MapPath("/"))
Search objFolder
上面的代码只是进行了一些变量初始化工作，真正的serach工作由下面这个Search函数执行。
Function Search(objFolder)
Dim objSubFolder
'循环搜寻当前文件夹中的每个文件
For Each objFile in objFolder.Files
Set objTextStream = objFSO.OpenTextFile(objFile.Path,1) <-- For Reading
'把文件内容读入一个变量
strFileContents = objTextStream.ReadAll
'如果在文件中找到该字符串，写个指到该文件的链接
If InStr(1, strFileContents, strSearchText, 1) then
Response.Write "<A HREF=""/" & objFile.Name &""">" & objFile.Name & "</A><BR>"
bolFileFound = True
End If
objTextStream.Close
Next
'以下是递归部分
' 如果其中有子目录，再调用Search函数
For Each objSubFolder in objFolder.SubFolders
Search objSubFolder
Next
End Function
该程序会自动搜索Web root目录以下的所有子目录，还不错吧？
（FSO要使用物理绝对路径，而不是Web Path的相对路径。例如，要打开的是c:\inetpub\wwwroot\temp\index.html，而不能是www.enfused.com/temp/index.html 或 /temp/index.html。要将后一种路径转换为物理绝对路径，使用Server.MapPath("filename")。）
随着文件和子目录数的增加，程序运行的时间会变长。所以如果是要提供繁重的搜寻功能，还是建议使用象 Microsoft Index Server这样的专业工具。
用FSO进行目录管理
现在知道FSO的好处了吧？下面我们尝试用FSO来做更复杂一些的工作。
Web目录管理就是在Web环境下进行文档的新建删除改名移动等工作，一个好的Web目录管理工具可以为用户提供一个与我们惯用的环境一样的操作方法来管理Web服务器上的文件。
那么先让我们来试试文件改名。首先要告诉大家，不幸得很，FSO不允许直接文件改名，所以我们要绕个弯进行。
<%
' 建立fso对象
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"
' 打开旧文件
set file = fso.opentextfile(path, 1) <-- 用于读
strText = file.readall
set file = nothing
' 检查是是否要建立文件夹
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
' 创建并写入新文件
set file = fso.Createtextfile(f.path & "\" & strNewFileName)
file.write(strText)
set f = nothing
file.close
set file = nothing
' 删除旧文件
fso.DeleteFile(path & "\" & rst("FileName") & i)
' 清除
set fso = nothing
%>
我们在这里特别举这个例子就是因为FSO在这个功能上存在缺陷，所以我们必须分两步走。首先新建一个文件，注意，由于用户可能将文件改名到另一个目录下，所以我们必须判断新目录是否存在（就是if not fso.folderexists那段代码）。新文件建好后，用fso.DeleteFile 将旧文件删除。
FSO功能上的弱点
FSO还是存在一些弱点。例如，它在处理二进制文件的时候就不那么方便。对于象MS Word文档，图像等许多文件，你只能执行移动，删除等操作，而不能打开，读/写。当然，FSO提供了另外一套操作它们的方法（具体请参考MSDN），但始终不如我们惯用的open方法那么顺手。
另一个不足与文件大小有关。由于FSO操作需要经常地将文件内容读入内存，文件有多大，就需要多少内存，所以如果你要处理大文件或一大堆小文件的话，内存的开销会很可观，可能会对系统运行速度有影响。解决办法是将大文件分段处理，并记住经常地清除内存（把变量设为null或""，set 对象=nothing）。
此外，FSO不能改变文件和文件夹的属性。例如，在建立guestbook的例子中，其实有一个安全机制我们没有实现，就是将保存信息的文件的属性设为只读，只有在更新的时候才临时改为可写，写完后再改回只读，许多用CGI或Perl写的guestbook程序都有这种功能，可惜用FSO无法实现该功能。
FSO还能干些什么？
总的来说，FSO还是很强大的。FSO还有一些一般没人注意到的很酷的功能。下面列出一些，当你看完可能会说“呀，我以前怎么不知道。”呵呵。
GetSpecialFolder 方法
返回一个特殊的Windows文件目录：Windows安装文件目录，系统文件目录，临时文件目录。使用方法分别是:FSO.GetSpecialFolder([0, 1, or 2])
GetTempName 方法
返回一个随机生成的临时文件或文件夹。象处理上面所说的将大文件分割处理的时候这个功能特别有用。（讨饭猫：如果Win98常死机的话，我们经常可以在Windows根目录下看到大量的长度为0的随机文件名，估计就是这个用途）
GetAbsolutePathName 方法
返回一个文件夹的绝对路径（有点象Server.MapPath）。例如，FSO.GetAbsolutePathName("region")会返回象"c:\mydocs\myfolder\region" 这样的路径，具体取决于你的当前目录。
GetExtensionName 方法
返回文件的扩展名。例如 FSO.GetExtensionName("c:\docs\test.txt") 返回 "txt"。
GetBaseName 和 GetParentFolder 方法
分别返回根目录名和父目录名。例如 FSO.GetParentFolder ("c:\docs\mydocs") 返回 "docs"。
Drives 属性
返回本机上所有驱动器的集合。如果你要建立一个explorer风格的界面，这个功能再有用不过。
记住要建立一套完善的错误信息处理机制，因为上面这些功能如果遇到象文件夹不存在之类错误时，会返回一些可恶的错误代码。
看到这里，是不是觉得FSO有用呢？实际上，我们所提到的内容只是冰山的一角。在Enfused等大站点上，还可以看到更多与此有关话题的讨论。
Copyright 1999-2000 internet.com Corp. All RIGHTS RESERVED.