BYsan

 找回密碼
 成為會員
搜索
熱搜: 活動 交友 discuz
查看: 2173|回復: 2

asp无组件上传的原理

[複製鏈接]
發表於 2005-6-13 13:28:28 | 顯示全部樓層 |閱讀模式
asp无组件上传的原理



一、无组件上传的原理
我&#36824;是一&#28857;一&#28857;用一&#20010;&#23454;例&#26469;&#35828;明的吧,客&#25143;端HTML如下。要&#27983;&#35272;上&#20256;附件,我&#20204;通&#36807;<input type="file">元素,但是一定要注意必&#39035;&#35774;置form的enctype&#23646;性&#20026;"multipart/form-data":
 樓主| 發表於 2005-6-13 13:28:56 | 顯示全部樓層
<form method="post" action="upload.asp" enctype="multipart/form-data">
<label>
<input type="file" name="file1" />
</label>
<br />
<input type="text" name="filename" value="default filename"/>
<br />
<input type="submit" value="Submit"/>
<input type="reset" value="Reset"/>
</form>


在后台asp程序中,以前&#33719;取表&#21333;提交的ASCII &#25968;据,非常的容易。但是如果需要&#33719;取上&#20256;的文件,就必&#39035;使用Request&#23545;象的BinaryRead方法&#26469;&#35835;取。BinaryRead方法是&#23545;&#24403;前&#36755;入流&#36827;行指定字&#33410;&#25968;的二&#36827;制&#35835;取,有&#28857;需要注意的是,一旦使用BinaryRead 方法后,再也不能使用Request.Form 或 Request.QueryString 集合了。&#32467;合Request&#23545;象的TotalBytes&#23646;性,可以&#23558;所有表&#21333;提交的&#25968;据全部&#21464;成二&#36827;制,不&#36807;&#36825;些&#25968;据都是&#32463;&#36807;&#32534;&#30721;的。首先&#35753;我&#20204;&#26469;看看&#36825;些&#25968;据是如何&#32534;&#30721;的,有&#26080;什么&#35268;律可循,&#32534;段代&#30721;,在代&#30721;中我&#20204;&#23558;BinaryRead&#35835;取的二&#36827;制&#36716;化&#20026;文本,&#36755;出出&#26469;,在后台的upload.asp中(注意&#35813;示例不要上&#20256;大文件,否&#21017;可能&#20250;造成&#27983;&#35272;器死掉):
<%
Dim biData, PostData
Size = Request.TotalBytes
biData = Request.BinaryRead(Size)
PostData = BinaryToString(biData,Size)
Response.Write "<pre>" & PostData & "</pre>" '使用pre,原&#26679;&#36755;出格式
' 借助RecordSet&#23558;二&#36827;制流&#36716;化成文本
Function BinaryToString(biData,Size)
Const adLongVarChar = 201
Set RS = CreateObject("ADODB.Recordset")
RS.Fields.Append "mBinary", adLongVarChar, Size
RS.Open
RS.AddNew
RS("mBinary").AppendChunk(biData)
RS.Update
BinaryToString = RS("mBinary").value
RS.Close
End Function
%>


&#31616;&#21333;起&#35265;,上&#20256;一&#20010;最&#31616;&#21333;的文本文件(G:homepage.txt,&#20869;容&#20026;"&#23453;玉:http://www.webuc.net";)&#26469;&#35797;&#39564;一下,文本框filename中保留默&#35748;值"default filename",提交看看&#36755;出&#32467;果:

-----------------------------7d429871607fe
Content-Disposition: form-data; name="file1"; filename="G:homepage.txt"
Content-Type: text/plain
&#23453;玉:http://www.webuc.net
-----------------------------7d429871607fe
Content-Disposition: form-data; name="filename"
default filename
-----------------------------7d429871607fe--

可以看出&#26469;&#23545;于表&#21333;中的&#39033;目,是用&#36807;"-----------------------------7d429871607fe"&#36825;&#26679;的&#36793;界&#26469;分隔成一&#22359;一&#22359;的,每一&#22359;的&#24320;始都有一些描述信息,例如:Content-Disposition: form-data; name="filename",在描述信息中,通&#36807;name="filename"可以知道表&#21333;&#39033;的name。如果有filename="G:homepage.txt"&#36825;&#26679;的&#20869;容,&#35828;明是一&#20010;上&#20256;的文件,如果是一&#20010;上&#20256;的文件,那么描述信息&#20250;多一行Content-Type: text/plain&#26469;描述文件的Content-Type。描述信息和主体信息之&#38388;是通&#36807;&#25442;行&#26469;分隔的。

嗯,基本上清晰了,根据&#36825;&#20010;&#35268;律我&#20204;就知道&#35813;怎么&#26469;分离&#25968;据,再&#23545;分离的&#25968;据&#36827;行&#22788;理了,不&#36807;差&#28857;忽略一&#20010;&#38382;&#39064;,就是&#36793;界值(上例中的"-----------------------------7d429871607fe")是怎么知道的?每次上&#20256;&#36825;&#20010;&#36793;界值是不一&#26679;的,&#36824;好&#36824;好asp中可以通&#36807;Request.ServerVariables( "HTTP_CONTENT_TYPE")&#26469;&#33719;之,例如上例中HTTP_CONTENT_TYPE&#20869;容&#20026;:"multipart/form-data; boundary=---------------------------7d429871607fe",有了&#36825;&#20010;,我&#20204;不&#20165;可以判&#26029;客&#25143;端的form中有&#26080;使用enctype="multipart/form-data"(如果&#27809;有使用,那么下面就&#27809;必要&#25191;行啦),&#36824;可以&#33719;取&#36793;界值boundary=---------------------------7d429871607fe。(注意:&#36825;里&#33719;取的&#36793;界值比上面的&#36793;界值&#24320;&#22836;要少"--",最好&#34917;充上。)

至于如何分析&#25968;据的&#36807;程我就不多&#36184;述了,&#26080;非就是借助InStr,Mid等&#36825;&#26679;的函&#25968;&#26469;分离出&#26469;我&#20204;想要的&#25968;据。

二、分&#22359;上&#20256;,&#35760;&#24405;&#36827;度
要&#23454;&#26102;反映&#36827;度&#26465;,&#23454;&#36136;就是要&#23454;&#26102;知道&#24403;前服&#21153;器&#33719;取了多少&#25968;据?再回想一下我&#20204;&#23454;&#29616;上&#20256;的&#36807;程,我&#20204;是通&#36807;Request.BinaryRead(Request.TotalBytes)&#26469;&#23454;&#29616;的,在Request的&#36807;程中我&#20204;&#26080;法得知&#24403;前服&#21153;器&#33719;取了多少&#25968;据。所以只能通&#36807;&#21464;通的方法了,如果我&#20204;可以&#23558;&#33719;取的&#25968;据分成一&#22359;一&#22359;的,然后根据已&#32463;上&#20256;的&#22359;&#25968;我&#20204;就可以算出&#26469;&#24403;前上&#20256;了多大了!也就是&#35828;,如果我1K&#20026;1&#22359;,那么上&#20256;1MB的&#36755;入流就分成1024&#22359;&#26469;&#33719;取,例如我&#24403;前已&#32463;&#33719;取了100&#22359;,那么就表明&#24403;前上&#20256;了100K。&#24403;我提出分&#22359;的&#26102;候很多人&#35273;得不可思&#35758;,因&#20026;他&#20204;都忽略BinaryRead方法不&#20165;是可以&#35835;取指定大小,而且可以&#36830;&#32493;&#35835;取的。

&#20889;&#20010;例子&#26469;&#39564;&#35777;一下分&#22359;&#35835;取的完整性,在&#21018;才的例子基&#30784;上(注意&#35813;示例不要上&#20256;大文件,否&#21017;可能&#20250;造成&#27983;&#35272;器死掉):

<%
Dim biData, PostData, TotalBytes, ChunkBytes
ChunkBytes = 1 * 1024 ' 分&#22359;大小&#20026;1K
TotalBytes = Request.TotalBytes ' &#24635;大小
PostData = "" ' &#36716;化&#20026;文本&#31867;型后的&#25968;据
ReadedBytes = 0 ' 初始化&#20026;0
' 分&#22359;&#35835;取
Do While ReadedBytes < TotalBytes
biData = Request.BinaryRead(ChunkBytes) ' &#24403;前&#22359;
PostData = PostData & BinaryToString(biData,ChunkBytes) ' &#23558;&#24403;前&#22359;&#36716;化&#20026;文本并拼接
ReadedBytes = ReadedBytes + ChunkBytes ' &#35760;&#24405;已&#35835;大小
If ReadedBytes > TotalBytes Then ReadedBytes = TotalBytes
Loop
Response.Write "<pre>" & PostData & "</pre>" ' 使用pre,原&#26679;&#36755;出格式
' &#23558;二&#36827;制流&#36716;化成文本
Function BinaryToString(biData,Size)
Const adLongVarChar = 201
Set RS = CreateObject("ADODB.Recordset")
RS.Fields.Append "mBinary", adLongVarChar, Size
RS.Open
RS.AddNew
RS("mBinary").AppendChunk(biData)
RS.Update
BinaryToString = RS("mBinary").value
RS.Close
End Function
%>

&#35797;&#39564;一下上&#20256;&#21018;才的文本文件,&#36755;出&#32467;果&#35777;明&#36825;&#26679;分&#22359;&#35835;取的&#20869;容是完整的,并且在While循&#29615;中,我&#20204;可以在每次循&#29615;&#26102;&#23558;&#24403;前&#29366;&#24577;&#35760;&#24405;到Application中,然后我&#20204;就可以通&#36807;&#35775;&#38382;&#35813;Application&#21160;&#24577;&#33719;取上&#20256;&#36827;度&#26465;。
 樓主| 發表於 2005-6-13 13:29:14 | 顯示全部樓層
另:上例中是通&#36807;字符串拼接的,如果是要拼接二&#36827;制&#25968;据,可以通&#36807;ADODB.Stream&#23545;象的Write方法,示例代&#30721;如下:

Set bSourceData = createobject("ADODB.Stream")
bSourceData.Open
bSourceData.Type = 1 'Binary
Do While ReadedBytes < TotalBytes
biData = Request.BinaryRead(ChunkBytes)
bSourceData.Write biData ' 直接使用write方法&#23558;&#24403;前文件流&#20889;入bSourceData中
ReadedBytes = ReadedBytes + ChunkBytes
If ReadedBytes > TotalBytes Then ReadedBytes = TotalBytes
Application("ReadedBytes") = ReadedBytes
Loop


三、保存上&#20256;的文件
通&#36807;Request.BinaryRead&#33719;取提交&#25968;据,分离出上&#20256;文件后,根据&#25968;据&#31867;型的不同,保存方式也不同:

&#23545;于二&#36827;制&#25968;据,可以直接通&#36807;ADODB.Stream&#23545;象的SaveToFile方法,&#23558;二&#36827;制流保存成&#20026;文件。
&#23545;于文本&#25968;据,可以通&#36807;TextStream&#23545;象的Write方法,&#23558;文本&#25968;据保存到文件中。
&#23545;于文本&#25968;据和二&#36827;制&#25968;据,是可以方便的相互&#36716;&#25442;的,&#23545;于上&#20256;小文件&#26469;&#35828;,&#20004;者基本上&#27809;什么差&#21035;。但是&#20004;种方式保存&#26102;&#36824;是有一些差&#21035;的,&#23545;于ADODB.Stream&#23545;象,必&#39035;&#23558;所有&#25968;据全部&#35013;&#36733;完才可以保存成文件,所以使用&#36825;种方式如果上&#20256;大文件&#23558;很占用&#20869;存,而&#23545;于TextStream&#23545;象,可以在文件&#21019;建好后,一次Write一部分,分多次Write,&#36825;&#26679;的好&#22788;是不&#20250;占用服&#21153;器&#20869;存空&#38388;,&#32467;合上面分析的分&#22359;&#33719;取&#25968;据原理,我&#20204;可以每&#33719;取一&#22359;上&#20256;&#25968;据就&#23558;之Write到文件中。我曾做&#36807;&#35797;&#39564;,同&#26679;本机上&#20256;一&#20010;200多MB的文件,使用第一种方式&#20869;存一直在&#28072;,到最后直接提示&#35745;算机&#34394;&#25311;&#20869;存不足,最可恨是即使&#36827;度&#26465;表示文件已&#32463;上&#20256;完,但是最&#32456;文件&#36824;是&#27809;有保存上。而使用后一种方法,上&#20256;&#36807;程中&#20869;存基本上&#26080;什么&#21464;化。

四、未解&#20915;的&#38590;&#39064;
我在博客&#22253;上看到Bestcomy描述他的Asp.Net上&#20256;&#32452;件是可以和Sever.SetTimeOut&#26080;&#20851;的,而在Asp中我是&#27809;能做到,&#23545;于上&#20256;大文件,就只有&#23558;Server.SetTimeOut&#35774;置&#20026;一&#20010;很大的值才可以。不知道有&#27809;有比&#36739;好的解&#20915;方法。

如果我&#20204;在保存文件&#26102;,使用TextStream&#23545;象的Write方法,那么如果用&#25143;上&#20256;&#26102;中&#26029;了文件&#20256;&#36755;,已&#32463;上&#20256;的那部分文件&#36824;是在的,如果可以&#26029;&#28857;&#32493;&#20256;就好了。&#20851;&#38190;&#38382;&#39064;是Request.BinaryRead方法&#34429;然可以分&#22359;&#35835;取,但是&#21364;不能跳&#36807;某一段&#35835;取!

五、&#32467;束&#35821;
原理基本上是&#35828;清楚了,但是&#23454;&#38469;代&#30721;要比&#36825;复&#26434;的多,要考&#34385;很多&#38382;&#39064;,最麻&#28902;在分析&#25968;据那部分,&#23545;于每一&#22359;&#33719;取的&#25968;据,要分析是不是&#23646;于描述信息,是表&#21333;&#39033;目&#36824;是上&#20256;的文件,文件是否已&#32463;上&#20256;&#32467;束……

相信根据上面的描述,您也可以&#24320;&#21457;出您自己功能&#24378;大的&#26080;&#32452;件上&#20256;&#32452;件。我想更多的人&#20851;心的只是代&#30721;,而不&#20250;自己&#21160;手去&#20889;的,也&#35768;&#27809;有&#26102;&#38388;,也&#35768;水平&#36824;不&#22815;,更多的只是已&#32463;成&#20026;了一种&#20064;&#24815;……我在CSDN上&#35265;&#36807;太多技&#26415;八股文——一段&#35828;明,然后全是代&#30721;。授人以&#40060;不若授人以&#28180;,&#32473;你一&#20010;代&#30721;,也&#35768;你并不&#20250;去思考&#20026;什么,直接拿去用,&#24403;下次碰到&#31867;似的&#38382;&#39064;的&#26102;候,&#36824;是不知道&#20026;什么,希望此文能&#35753;更多人&#23398;到&#28857;什么,最重要是“悟”到&#28857;什么!
您需要登錄後才可以回帖 登錄 | 成為會員

本版積分規則

小黑屋|手機版|Archiver|BYsan

GMT+8, 2024-4-29 04:05 AM , Processed in 0.042830 second(s), 15 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回復 返回頂部 返回列表