【ASP】文件上传

来源:互联网 发布:剑三喜子捏脸数据 编辑:程序博客网 时间:2024/06/06 14:50

由于VBScript这门古老的编程语言并没有像ASP.NET,Servlet、Struts2,PHP等封装好文件上传的方法,绝对不可能一个request.form["file"]就能够拿到文件,因此处理文件上传是很艰难的,需要自己截获HTTP传递过来的二进制报文,进行报文中的二进制字符切割,才能拿到文件以及我们想要的信息,不过这也更接近底层,更能让我们清楚HTTP文件上传的原理。

网上一些文章的VBScript的文件上传写得天华龙凤,短短的3KB代码居然能写到16KB,让人完全看不懂在干什么。或者就是用a,b,c命名,完全不知道怎么修改。而且大多数流传下来的文章都没有考虑到如果此网站是UTF-8编码的问题,容易造成乱码,毕竟文件上传涉及二进制操作,不是一句简简单单的Response.Charset="UTF-8"然后加个<%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>就能完成的事,还需要对二进制文件流的编码进行修改。甚至还有些是用AspUpload来做,你不可能保证任何一个服务器都有这个组件吧?这会严重影响迁移问题。

下面,将为大家剖析如何在ASP做文件上传,让大家也写出属于自己的文件上传类!

将完成,如下图的一个文件系统:


不仅能够完成文件上传,还能自定义服务器保存文件的文件名,比如这里以原文件名+时间戳的方式保存文件,获取用户上传的后缀(你可以据此进一步加工,限定用户上传的文件类型了)等。

具体制作过程如下:

1、首先是这个工程的目录结构:


在进行代码写作之前,请保证你网站,至少是upload_file文件夹的Web共享是打开的,在属性界面有如下图的属性:


同时,Internet来宾账户有读取、写入的权限。


不然,有可能出现二进制流无法写入文件的情况,然而VBScript这门古老的编程语言是不会报错的,每次处理二进制流出现问题,它就给你看一个完全空白页面,就只会沉默,不跟你沟通,很蛋疼的。

2、之后是upload.html这个上传表单,本来没什么好说的,主要是表单有两个小地方需要注意的,这个表单必须给file标好name,同时表示这个表单是扔二进制数据上去upload.asp,同时必须用post的方式,而不是简简单单的文件。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>文件上传</title></head><body>    <form method="post" action="upload.asp" enctype="multipart/form-data"><!--一定要有enctype="multipart/form-data",表示这个表单是传递二进制数据的,同时不能再传一些text,password这些无关的文件域上去了。-->        <input type="file" name="file"/><!--这里的file文件域,就是一定要有name属性,虽然在之后的二进制处理根本没有用到这个name,你随便给个名称都行,但就是要有-->        <input type="submit" value="提交" />    </form></body></html>

如果这个file域没有name属性的话,无论你上传什么东西,upload.asp接受到的二进制流就只能是如下的东西,换句话说,是无法接受文件的。


3、最后就是这个工程的精华,upload.asp。

首先,你完全可以在upload.asp写入如下的代码:

<%filesize=Request.TotalBytesfiledata=Request.BinaryRead(Request.TotalBytes)response.BinaryWrite(filedata)%>

将接受到的二进制数据打印出来,比如你将C盘的一个内容如下的aa.txt文件在upload.html的表单提交给upload.asp的话:


上述的代码,在upload.asp打印出来的东西如下:


接下来,你的目标很明了,就是对这串二进制字符进行切割,这串二进制内容里面有我们想要的一切信息,包括文件内容、客户端上传的文件名,

里面的-----------------7e010b37206c4其实是条分割线来的,如果你的表单里面有多个带name的文件域,则你会发现系统会用-----------------7e010b37206c4将多个文件报文分割。

同时,这里有部分回车在IE6浏览器中显示不出来,你可以用查看源代码的方式,看得一清二楚。

upload.asp具体代码如下所示:

<%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%><%'禁止缓存'Response.CacheControl="no-cache"  Response.Expires=-1Response.Charset="UTF-8"    '配合第一行设定网页编码if Request.TotalBytes then'如果上传文件非空'set read_stream=createobject("adodb.stream")'设置一个流'read_stream.Type=1'这个流读二进制数据,如果Type=2则读文本数据'read_stream.Open'打开流'read_stream.write Request.BinaryRead(Request.TotalBytes)'将表单传过来的二进制数据写入流read_stream''将流read_stream的所有数据读到binary_stream中,binary_stream相当于一个临时变量,接下来将对binary_stream进行切割,以免污染read_stream中的原数据'read_stream.Position=0binary_stream=read_stream.Readenter=chrB(13)&chrB(10)'二进制流中的回车'first_enter=clng(instrb(binary_stream,enter))'寻找第一个回车的位置'second_enter=instrb(first_enter+1,binary_stream,enter)'寻找第二个回车的位置'set write_stream=createobject("adodb.stream")'定义一个流write_stream'write_stream.type=1'write_stream是处理二进制数据的'write_stream.open'将read_stream中文件信息部分写到write_stream'read_stream.Position=first_enter+1read_stream.copyto write_stream,second_enter-first_enter-3write_stream.Position=0write_stream.type=2'再将write_stream转为文本流'write_stream.CharSet="UTF-8"file_info=write_stream.readtext'写到file_info这个字符串'write_stream.Close'暂且关闭write_stream这个流,接下来对file_info这个字符串进行切割'file_name=mid(file_info,instrRev(file_info,"\")+1)'取得全文件名'file_pre_suffix=left(file_name,instrRev(file_name,".")-1)'取得文件前缀'suffix=mid(file_name,instrRev(file_name,"."))'取得文件后缀,带.的'   server_file_name=file_pre_suffix&"_"&datediff("s","1970-01-01 00:00:00",now)&suffix'在服务器保存的文件名就是“原文件前缀_时间戳.原文件后缀名”'delimiter=leftB(binary_stream,clng(instrb(binary_stream,enter))-1)'取得-----------------7e010b37206c4这个文件分隔符,用于给字符串处理函数找到文件内容'third_enter=instrb(second_enter+1,binary_stream,enter)'找第三个回车的位置'file_begin_position=clng(instrb(third_enter+1,binary_stream,enter))+1'获取文件内容第一个字符之前的位置'file_end_position=clng(instrb(lenb(delimiter),binary_stream,delimiter))-3  '获取文件内容中最后一个字符的位置,就是第二个分隔符"delimiter"开始的前一个二进制字符'write_stream.type=1'write_stream是处理二进制数据'write_stream.openread_stream.Position=file_begin_position'将流read_stream的开始位置移到文件开始的位置'read_stream.copyto write_stream,file_end_position-file_begin_position'把流read_stream的开始位置之后 长为 文件长度 的内容复制到write_stream,其中文件长度就是文件结束的位置file_end_position-文件开始的位置file_begin_position'write_stream.SaveToFile server.mappath("upload_file/"&server_file_name),2'将write_stream转化为文件,保存在设定好的文件目录''人走带门,关闭所有用到的流'write_stream.CloseSet write_stream=nothingread_stream.CloseSet read_stream=nothing'打印文件信息到网页'response.write "你上传的文件是:"&file_name&"<br>"response.write "你上传文件的后缀为:"&suffix&"<br>"url="http://"&Request.ServerVariables("HTTP_HOST")&"/my_asp/upload/upload_file/"&server_file_nameresponse.write "访问地址:<a href='"&url&"' target='_blank'>"&url&"</a><br>"response.write "<a href='upload.html'>返回</a><br>"    end if%>

上述代码做的事,如下图所示:


说白了就是一个字符串切割的过程,虽然这个字符串切割过程有点复杂。

利用instr函数来确定字符在字符串位置,InStr(string1,string2)返回的是string2在string1出现的位置。例如:

SearchString="XXpXXpXXPXXP"'被搜索的字符串。SearchChar="P"'要查找字符串"P"。MyPos=Instr(SearchString,SearchChar)'返回9。

而Clng则是强行讲其转化为long型。

至于LEFT函数用于从一个文本字符串的第一个字符开始返回指定个数的字符,例如:

AnyString = "Hello World" '定义字符串。MyStr = Left(AnyString, 1) '返回 "H"。MyStr = Left(AnyString, 7) '返回 "Hello W"。MyStr = Left(AnyString, 10) '返回 "Hello Worl"。

而Mid函数用法如下:

Mid(String As Variant, Start As Long, [Length As Variant]) As Variant

String,必选。变体(字符串)表达式,要被截取的字符。如果该参数为Null,则函数返回Null。

Start,必选。数值表达式,从左起第几位开始截取。

Length,可选,从Start参数指定的位置开始,要向右截取的长度。如果省略,将指定为从Start参数位置开始向右到字符串结尾的所有字符数。

例子如下:

v=Mid("VisualBasic",0,12)'提示实时错误5v=Mid("VisualBasic",1,6)'v的值为"Visual"v=Mid("VisualBasic",1,20)'v的值为"VisualBasic"v=Mid("VisualBasic",8)'v的值为"asic"v=Mid("VisualBasic",15)'v的值为空字符串v=Mid("中文VB",2,2)'v的值为"文V"

当然还有right函数,不过left与带参数与不参数的mid函数足矣。

其实这些函数都是从Excel里面来的。唯一需要注意的是,在VBScript需要严格区分二进制的流的截取和字符串的截取,截取二进制里面的东西函数后面都补一个b,例如找二进制中字符出现的位置用instrb而不是原版的instr,instr是用来处理文本、字符串的。

form表单传递过来的一个二进制流,而部分二进制流的文本信息部分被转化为字符串来保存,这需要区别对待的。


通过,上述的例子,你就可以在ASP中实现文件上传了,配合《【ASP】利用MVC分层结构,优化ASP的登录系统的写作》(点击打开链接),你可以利用Access2003+记事本+IIS服务器,写出一个需求不大但严格要求不能在服务器乱装东西的小网站。这也是当年XP刚刚出来的时候,辉煌一时的建站方式。当然,现在的Windows2003一般都在跑SQL Server+ASP.NET了,不过研究一下前辈的东西有好处的。

1 0
原创粉丝点击