吴泽勋
虚拟主机中实现文件的上传下载
发表于《闽西职业大学学报》(ISSN 1008-4797 CN35-1220/G4)第7卷 第4期(2005.4)


摘要:廉价的虚拟主机是个人或中小型企业用户构建网络服务器的常用方式,文件的上传和下载是网络中常用到的功能。分别以是否有上传组件和存放在服务器硬盘还是存放在数据库中完整地讨论了虚拟主机下完成文件的上传和下载功能。
关键字:虚拟主机;上传;下载;ASP;数据库

File Upload and Download in the Virtual Host
Abstract: The cheap Virtual Host is the common use way that personal or medium small scaled business enterprise customer sets up the network server.Filing of upload and download is the common use of network function.The thesis discusses the upload and download function of the Virtual Host to complete the file whether upload the composition and the deposition in the server hard.
Key Words: Virtual Host; Upload;download; ASP; DataBase

    现在Internet发展非常迅速,无论个人或企业都想在Internet上安个家。对于个人或中小型企业来讲自己构架服务器,接入专线,从技术和资金方面都是无法承受的。有一种最实惠的方式就是申请虚拟主机,按现在的市场价来讲,申请一个域名加虚拟主机每年才200元到1000元之间。那什么是虚拟主机,虚拟主机能支持什么功能呢?
    虚拟主机(Virtual Host/ Virtual Server)是使用特殊的软硬件技术,把一台计算机主机分成一台台“虚拟”的主机,每一台虚拟主机都具有独立的域名和IP地址(或共享的IP地址),具有完整的Internet服务器功能。在同一台硬件、同一个操作系统上,运行着为多个用户打开的不同的服务器程序,互不干扰;而各个用户拥有自己的一部分系统资源(IP地址、文件存储空间、内存、CPU时间等)。虚拟主机之间完全独立,在外界看来,每一台虚拟主机和一台独立的主机的表现完全一样。一般虚拟主机根据操作系统进行分类,目前基本分为Windows2000系列和Linux系列主机。
    在虚拟主机中实现文件的上传下载,首先必须要有上传的界面。其次必须考虑上传后服务器对上传文件的处理方式,如果服务器支持上传组件,可以直接使用组件;如果不支持组件,只能使用纯代码来实现。最后必须考虑上传文件在服务器上的存放,可以分两种:放在服务器的本地硬盘或放在服务器上的数据库中。如果存放到数据库中,必须在服务器中建立一个数据库,以下讨论假设已经在服务器根目录下建好了一个Microsoft Access的数据库,库名为bc.mdb,库内有一表名为wj,表中含ID(自动编号)和wj(OLE对象)两字段。下面以支持ASP的Windows虚拟主机为例分步骤把所有情况讨论一下。
一、上传界面的实现
    无论使用何种开发语言,使用何种方法,都必须先提供给用户一个上传界面,可以让用户选择要上传的文件。在RFC1867中对于HTTP的文件上传引入了一种简单而功能强大的方法,就是在表单中定义一个新类型:<INPUT TYPE=“FILE”>。此方式可以在表单中加入multipart/form-data编码方案。界面显示采用了的“浏览...”按钮,用户能很容易的使用本地的“打开文件...” 对话框选择要上传的文件。具体代码如下(文件名为sc.htm):
<form name=“frmSc” enctype=“multipart/form-data” action=“bc.asp” method=post>
  <input type=file name=myfile>
<input type=submit name=ok value=“提交”>
        </form>
    这样在sc.htm网页中自动生成一个“浏览”按钮,单击“浏览”按钮可以选择要上传的文件。如下图:


二、文件上传的实现
(一)、 使用上传组件(ASPUpload)实现
ASPUpload作为Windows虚拟主机中最常见也最为典型的上传组件。以此为例,具有一定的代表性。下面以上传到服务器本地硬盘和上传到服务器数据库分别论述。
1、 上传到服务器的本地硬盘
    首先设置数据可以存入缓存区中,然后创建一个上传组件,使用该组件的Save方法把上传的文件以原文件名的形式保存到服务器的某个目录(如:temp)。Save方法只有一个参数,即文件保存的路径。文件路径尽可能地使用Server.MapPath()来表示存储在服务器上的文件路径,而不要用静态绝对路径。主要代码如下(bc.asp):
Response.Buffer=True
’创建文件上传组件
Set objSc=Server.CreateObject(“Persits.Upload.1”)
'将客户端文件保存到WEB服务器端的本地硬盘上
i=objSc.Save(Server.MapPath(“\temp”))

2、 将文件存在数据库中
    将文件保存在数据库中主要用了ASPUpLoad组件中文件对象的ToDatabase方法。ToDatabase方法带有两个参数,第一个参数表示数据库的连接对象,第二个参数表是执行的SQL语言,主要代码如下(bc.asp):

‘创建文件上传组件
Set Upload=Server.CreateObject(“Persits.Upload.1”)
Count=Upload.Save(Server.MapPath(“\temp”))
‘创建组件中的文件对象FileUpload
Set objFile=Upload.Files(“FileUpload”)
‘插入数据的SQL语句
Sql=“insert into wj (wj) values (?)”
‘连接到数据库
Conn=“driver={Microsoft Access Driver (*.mdb)};DBQ=” & Server.MapPath(“bc.mdb”) & “;”
‘执行ToDatabase方法
Response.Write SQLFileObj.ToDatabase Conn,Sql

(二) 、组件上传文件的实现
    大部分的Internet服务商的虚拟主机都没有提供上传组件,为了能在这种虚拟主机中上传文件,必须使用纯代码来完成。下面以Windows的虚拟主机为例,使用纯ASP代码实现上面的功能。
    在设计本功能前必须先了解一下将要使用到的ASP的对象和方法。用来获取上一个页面传递过来的数据一般是使用Request对象。同样的,也可以使用Request对象来获取上传上来的文件数据,使用的方法是Request.BinaryRead()。而要从数据库中读出来文件的数据显示到网页上面要用到的方法是: Request.BinaryWrite()。在得到了文件的数据,要保存到数据库中的时候, 不可以直接使用Insert语句对数据库进行操作,而是要使用ADO的 AppendChunk方法,同样的,读出数据库中的文件数据,要使用GetChunk方法。还有,如果上传到服务器硬盘的话,还要使用到ADO.STREAM对象,它可以同时操作文本对象和二进制对象,利用它就可以在ASP中直接实现文件上传过程中的读写操作。下面具体实现无组件上传功能。
1、 上传到服务器的本地硬盘
    首先创建两个STREAM对象,其中一个为源数据流,即接收初始的二进制数据;另一个为目的数据流,即接收来自经源数据流处理后的数据,并最终保存为所需的文件。为什么处理呢?因为传上来的文件除了上传的文件信息外,含有其他“杂质”---该文件在用户硬盘上的路径、类型、提交页面的表单等相关信息的描述。在保存文件时,必须把“杂质”除去。如何除去“杂质”?使用STREAM对象中CopyTo函数,根据CopyTo函数的用法,首先在源数据流中定位文件开始的位置,并且求出文件内容的长度,将真正的文件数据复制到目的数据流中,并使用SaveToFile方法保存文件。具体源代码如下(bc.asp):
‘stmInit为源数据流,用来接收上传上来的原始数据
set stmInit=server.CreateObject(“ADODB.Stream”)
stmInit.Mode=3 ‘设置打开模式,3为可读可写
stmInit.Type=1 ‘设置数据类型,1为二进制数据
stmInit.Open
‘stmDesc为目标数据流,用来保存除去“杂质”后的文件
set stmDesc=server.CreateObject(“ADODB.Stream”)
stmDesc.Mode=3
stmDesc.Type=1
stmDesc.Open
‘接收上传文件数据到stmInit
FormSize=Request.TotalBytes
FormData=Request.BinaryRead(FormSize)
stmInit.Write FormData ‘ 赋值源数据流
‘除去“杂质”
CLStr=ChrB〔13〕 & ChrB〔10〕
DataStart=InStrB(FormData,CLStr & CLStr)+4
'4是两对回车换行符的长度
DivStr=LeftB(FormData,InStrB(FormData,CLStr)-1)
DataSize=InStrB(DataStart+1,FormData,DivStr)-DataStart-2
‘把除去杂质的文件数据给stmDesc,并保存
stmInit.Position=DataStart ‘position指出文件的开始位置
stmInit.CopyTo stmDesc, DataSize
‘复制给stmDesc,DataSize表示文件的长度
stmDesc.SaveToFile Server.MapPath(“\temp”) & strFileName,2 ‘保存文件
‘关闭所有STREAM对象
stmDesc. Close
Set stmDesc=Nothing
stmInit. Close
Set stmInit=Nothing

2、 上传到服务器的数据库中
    和上面的一样,要在bc.asp中对从浏览器中获取的数据进行必要的处理,因为我们在sc.asp中获取到的数据不仅仅包含了我们想要的上传上来的文件数据还有的无用的信息,我们需要剔除冗余数据,并将处理过的文件保存到数据库中。具体代码如下(bc.asp):

Response.Buffer=True ‘输出缓冲为真
‘除去杂质后
set Conn=server.CreateObject(“ADODB.connection”)
Conn.ConnectionString=“driver={Microsoft Access Driver (*.mdb)};DBQ=” & Server.MapPath(“bc.mdb”) & “;uid=;PWD=;”
‘连接数据库
Conn.Open
set rs=Server.CreateObject(“ADODB.recordset”) ‘打开记录集
rs.Open “SELECT * FROM [images] where id is null”,Conn,1,3
rs.AddNew
rs(“wj”).AppendChunk FormData ‘加入数据库中
rs.Update

    好了,这样就把上传来的文件保存到了名为wj.mdb的数据库中。
三、文件的显示或下载
(一)、 保存在服务器硬盘的文件显示或下载
这种情况的显示和下载是非常简单的,只要直接建立一个指向此文件的连接即可,比如说在服务器上的存放地址为”\temp\1.doc”(在服务器temp目录的1.doc文件),建立一个连接如下:单击此处下载
(二)、 保存在数据库中的文件的显示或下载
    从数据库中显示,可以根据ID号读出来符合条件的数据,然而读出的文件是二进制流的形式,如果要正确显示出来必须告诉浏览器是什么文件类型,而ASP中的Response对象有一个叫ContentType的属性,它定义服务器发送给客户端内容的MIME类型。什么是MIME?如在网页编程中如果将超链接指向一个Word或Excel文件,当用户点击这个链接时浏览器会自动调用对应方法将这个文件打开。之所以能做到这点就是因为用户机器上安装Office后会在浏览器中注册对应的MIME资源类型。对应不同的文件类型我们只需设置ContentType,就可以正确显示文件。主要代码如下(show.asp):

‘打开数据库连接后
Set rs=server.createobject(“ADODB.recordset”)
Sql=“select img from images where id=” & trim(strID)
rs.Open Sql,Conn,1,1
‘显示文件的类型,可在此设置相应的MIME类型
Response.ContentType = “*/*”
Response.BinaryWrite rs(“wj”).GetChunk(7500000)

    好了,到此为止,讨论了在常见建站方式-廉价的虚拟主机中实现文件的上传、下载的整个过程,在实现过程中,针对较多使用的Windows虚拟主机可能出现的各种情况分别作了讨论,为在Windows虚拟主机中实现文件的上传下载提供了一个完整的解决方案。


参考文献:
[1]廖信彦.ActiveServerPage应用大全[M].北京:清华大学出版社,2000.
[2]李福荣.ASP动态网站之旅[M].北京:人民交通出版社,2000.
[3]位元文化.ASP3.0动态网页实务经典[M].北京:中国青年出版社,2000.
[4]汪晓平.ASP网络开发技术[M].北京:人民邮电出版社,2000.