这个问题已经不是什么新鲜问题了,网上也有大把的教程,但大多数是授人以鱼,而不授人以渔,经过辛苦的资料收集,思考,调试,整理,我基本上已经把这个问题从原理上搞清楚了,现在根据我自己的理解,在范例程序的基础上,加以解释,希望能对部分网友(比我还菜的:-))有所帮助。
请诸位大虾能对其中的不正或不良这处予以指正。
程序中stream对象的用法上参考了“化境HTTP上传程序 Version 2.0”在代码,在此对稻香老农和梁无惧表示衷心的感谢和由衷的敬意。
先来分析一下,为后面的数据分析算法打点基础,以下是我摘录的一小段网页中提交的二进制数据:
-----------------------------7d31ec15102d0
Content-Disposition: form-data; name="txtTitle"
满脑的想法
-----------------------------7d31ec15102d0
Content-Disposition: form-data; name="filImage"; filename="F:\material\木纹背景\pic016.jpg"
Content-Type: image/pjpeg
?? JFIF ? C
!!E.'.EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE??" ?
? ? } !1AQa"q2亼?#B绷R佯$3br?
侼s歊J佦=ǜ珻,%??Xm 銓鼽?幮??驲湕胄滙C?
儗 g?咶? tS?B矠:u隠c
g不t凄L琰h`啨0p
g殲41?9'$筵奆]眬?膁?摍? 渦"???
-----------------------------7d31ec15102d0
Content-Disposition: form-data; name="btnUpload"
Upload
-----------------------------7d31ec15102d0--
蓝色的字符的内容我们应该熟悉吧,中间的乱码就是上传的文件的内容,其实我们要做的就是将这一堆数据进行分析,挑出对我们有用的数据保存下来就OK了。分析数据就是查找一些标志性的内容,如回车换行符,“----------”符号,用两个指针确定两个位置,然后提取数据,我的算法不知道好不好,本人的数据结构是学得很烂的,十分sorry。
以下是一个完事的应用,其中的类定义可以与入另一个文件,使用的时候只要用
<!--include file="LjUpload.cls"-->
命令包含进来就可以了。
LjUpload.asp:
<%@ Language=VBScript %>
<% option explicit %>
<script language=vbscript runat=server>
private srmRequestData'adodb.stream对象,保存从form中提交来的所有数据
private adTypeBinary'adodb.stream对象的叁数:返回二进制数据
private adTypeText'adodb.stream对象的叁数:返回文本数据
private adModeRead'adodb.stream对象的叁数:对象可读
private adModeWrite'adodb.stream对象的叁数:对象可写
private adModeReadWrite'adodb.stream对象的叁数:对象可读写
class LjUpload'定义一个类,名称为LjUpload。
private bytCrLf'单字节的回车换行符,共2字节
private bytSub'单字节的“-”符号,共8字节
private binData'二进制数据变量,保存一个提交数据的复本,便於操作
private dicForm'保存form文本域的信息
private dicFile'保存form文件域的信息
private strName'form表单的输入域名称
private strValue'form表单的输入域值
private objFile'文件信息对象,保存文件相关的信息,具体叁看class LjFile的定义
private posB'二进制数据读写指针,开始指针
private posE'二进制数据读写指针,结束指针
public Charset'语言属性设置
private sub Class_Initialize'类初始化过程
bytCrLf = getSBfromDB(vbcrlf)
bytSub = getSBfromDB("--------")
Charset = "gb2312"'默认语言属性设置为简体中文:gb2312
adTypeBinary = 1'返回二进制数据
adTypeText = 2'返回文本数据
adModeRead = 1'对象数据可读
adModeWrite = 2'对象数据可写
adModeReadWrite = 3'对象数据可读写
end sub
public sub GetData'类的打开过程,上传文件及分析数据的过程
set srmRequestData = server.CreateObject("adodb.stream")'建立一个adodb.stream对象
srmRequestData.Type = adTypeBinary'指定返回数据类型
srmRequestData.Mode = adModeReadWrite'指定打开模式
srmRequestData.Open'打开对象
srmRequestData.Write request.BinaryRead(request.TotalBytes)'获取所有form提交的数据
srmRequestData.Position = 0'读写指针重新定位至对象头部,写数据,指针已指向对象尾
binData = srmRequestData.Read'在变量中保存提交数据的复本,便於操作
set dicForm = server.CreateObject("scripting.dictionary") '用来保存文本信息
set dicFile = server.CreateObject("scripting.dictionary") '用来保存文件信息
posB = instrb(binData,bytSub)'开始分析所获取的二进制数据
posB = instrb(posB,binData,bytCrLf) + 2 '+2是加入回车换行符本身的长度
posB = instrb(posB,binData,getSBfromDB("name=""")) + 6
do until posB = 6'控制条件的设置有多种方式,这里的仅供叁考
posE = instrb(posB,binData,getSBfromDB(""""))
strName = getTextfromBin(srmRequestData,posB,posE-posB)
posB = posE + 1 '指针移动到“"”的後面
posE = instrb(posB,binData,bytCrLf)
if instrb(midb(binData,posB,posE-posB),getSBfromDB("filename=""")) > 0 then '这是一个file域
posB = instrb(posB,binData,getSBfromDB("filename=""")) + 10
posE = instrb(posB,binData,getSBfromDB(""""))
set objFile = new LjFile'建立一个文件信息对象
if posE>posB then
objFile.FileName = getFileNamefromPath(getTextfromBin(srmRequestData,posB,posE-posB))'写入文件名称
posB = instrb(posB,binData,getSBfromDb("Content-Type:")) + 14
posE = instrb(posB,binData,bytCrLf)
objFile.ContentType = getTextfromBin(srmRequestData,posB,posE-posB)'写入文件类型
posB = posE + 4'这个地方换了两行,具体叁看输出的原始二进制数据
posE = instrb(posB,binData,bytSub)
objFile.FileBegin = posB
objFile.FileLen = posE-posB-2'写入文件长度信息,-2是减去一个回车符
end if
dicFile.Add strName, objFile
set objFile = nothing'释放文件信息对象
else'这是一个文本域
posB = posE + 4 '这个地方换了两行,具体叁看输出的原始二进制数据
posE = instrb(posB,binData,bytSub) - 2
strValue = getTextfromBin(srmRequestData,posB,posE-posB)
dicForm.Add strName, strValue
end if
posB = posE + 2
posB = instrb(posB,binData,bytCrLf) + 2
posB = instrb(posB,binData,getSBfromDB("name=""")) + 6
loop'当循环结束时分析二进制数据完成
end sub
private function getTextfromBin(srmSource,posBegin,posLen)'二进制数据转换为字符串,包括汉字
dim srmObj, strData
set srmObj = server.CreateObject("adodb.stream")
srmObj.Type = 1
srmObj.Mode = 3
srmObj.Open
srmSource.position = posBegin-1 '位置计数首数不一样,这个对像是对0开始的
srmSource.CopyTo srmObj,posLen
srmObj.Position = 0
srmObj.Type = 2
srmObj.Charset = Charset'语言属性设置
strData = srmObj.ReadText
srmObj.Close
set srmObj = nothing
getTextfromBin = strData
end function
private function getSBfromDB(bytString)'双字节字符串转换成单字节字符串
dim bin, i
bin = ""
for i=1 to len(bytString)
bin = bin & chrb(asc(mid(bytString,i,1)))
next
getSBfromDB = bin
end function
||||||private function getDBfromSB(bitString)'单字节字符串转换成双字节字符串
dim str, i
str = ""
for i=1 to lenb(bitString)
str = str & chr(ascb(midb(bitString,i,1)))
next
getDBfromSB = str
end function
private function getFileNamefromPath(strPath)'从一个完整路径中析出文件名称
getFileNamefromPath = mid(strPath,instrrev(strPath,"\")+1)
end function
public sub about()'关於类过程
dim html
html = "<table border=1 cellpadding=2 cellspacing=1>" & "<tr>" & _
"<td style='font-family:verdana;' bgcolor=yellow> <marquee width=160 " & _
"onmouseover='this.stop();' onmouseout='this.start();'>" & _
"<a href=mailto:java300@163com target=_blank>LiJun Upload Class V1.0</a>" & _
"</marquee> </td>" & "</tr>" & "</table>"
Response.Write html
end sub
public function Form(strFormName)'求表单内容的函数
if dicForm.Exists(strFormName) then
Form = dicForm(strFormName)
else
Form = ""
end if
end function
public function File(strFormName)'求文件内容的函数
if dicFile.Exists(strFormName) then
set File = dicFile(strFormName)
else
set File = new LjFile
end if
end function
private sub Class_Terminate'类终止过程
dicForm.RemoveAll
set dicForm = nothing
dicFile.RemoveAll
set dicFile = nothing
srmRequestData.Close
set srmRequestData = nothing
end sub
end class
class LjFile'文件类
public FileName'文件名
public ContentType'文件类型
public FileBegin'文件数据开始位置
public FileLen'文件长度,字节数
private sub Class_Initalize
FileName = ""
ContentType = ""
FileBegin = 0
FileLen = 0
end sub
public sub SaveToFile(FilePath)'文件保存到磁盘上,FilePath为完整路径,包括文件名
dim srmObj
set srmObj = server.CreateObject("adodb.stream")
srmObj.Type = adTypeBinary
srmObj.Mode = adModeReadWrite
srmObj.Open
srmRequestData.Position = FileBegin-1
srmRequestData.CopyTo srmObj, FileLen
srmObj.Position = 0
srmObj.SaveToFile FilePath, 2'如果该文件已经存在,无条件覆盖,以後根据需要再行完善
srmObj.Close
set srmObj = nothing
end sub
public function GetBinaryData()
srmRequestData.Position = FileBegin-1
GetBinaryData = srmRequestData.Read(FileLen)
end function
end class
</script>
<HTML>
<HEAD>
<META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0">
<meta http-equiv="content" content="text/html;charset=gb2312">
<TITLE>ASP无组件上传类:LjUpload</TITLE>
</HEAD>
<BODY>
<%
if request.ServerVariables("REQUEST_METHOD") = "POST" then
dim upload
set upload = new LjUpload
upload.Charset = "gb2312"'设置文本信息的语言属性
upload.GetData()
dim title, filImage
title = upload.Form("txtTitle")
Response.Write title & "<br>"
set filImage = new LjFile'这句可不用,此处仅为写代码方便
set filImage = upload.File("filImage")
Response.Write filImage.FileName & "<br>"
'以文件形式保存到磁盘,文件名是当前日期时间的处理值
filImage.SaveToFile server.MapPath("./") & "\" & replace(replace(replace(now(),"/","_")," ","_"),":","_") & "." & right(filImage.FileName,3)
'保存到数据库用以下的代码
'dim cn, rs, sql
'set cn = server.CreateObject("adodb.conne