43434 ID:faintbear
108207次访问,排名752好友0人,关注者0
faintbear的文章
原创 122 篇
翻译 0 篇
转载 4 篇
评论 32 篇
小力力力的公告
最近评论
Xinyie:在/root/下新建了个文件test.cron,里边写了 :
*/1 * * * * echo hello world >> test.txt,然后
crontab test.cron
在/var/spoon/cron/下有了Xinyie文件,但是 crontab -e时:
在/va/bin/sh: line 1: /bin/vi: 没有那……
cp:有整个的源码没有
海炫:博客“选美”大赛请你当评委!令人瞩目的中国第一款女性车博客大赛开幕了,美女、美图琳琅一堂,最后哪位丽人有资格领得靓车归呢?博客大赛请你当评委。凡参与参加跟贴投票的博客都将有机会赢取奖品一份。同时,也欢迎介绍您的女性亲朋好友来参加此次“海炫《女性.车》博客大赛”。原创与车有关的文章、照片均可参加,参赛选手人人有奖,大奖: 最新款海炫女性车一辆! 参赛地址:http://hyshine.boke……
飞鸟:很好,支持,
jun:还可以
文章分类
收藏
    相册
    GF的照片
    文件图片
    都是自己淫
    ♂Blue & → 安仔 ←
    echo妞儿
    一笑聊斋
    云烟*过客*独醉的专栏
    我的BlogJava的家
    我喜欢的blog&site
    IBM技术专区
    java的Blog
    oracle学习jaguarcts的专栏
    不错得论坛
    喜欢的blog
    天魔窟
    安全天使
    很多不错的blog
    我的一片天
    智在居士草堂
    项目学习
    blog---hibernate
    oracle 下载好啊~
    ZDnet 不错
    天乙社区
    学习日记
    英语学习
    万千英语族~~很棒的(RSS)
    英语听力
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 asp无组件上传的原理 (转)收藏

    新一篇: oracle sql总结 | 旧一篇: ORACLE PL/SQL 基础2 (游标的学习)

     

    出处:宝玉BLOG

    一、无组件上传的原理
    我还是一点一点用一个实例来说明的吧,客户端HTML如下。要浏览上传附件,我们通过<input type="file">元素,但是一定要注意必须设置form的enctype属性为"multipart/form-data":


    <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程序中,以前获取表单提交的ASCII 数据,非常的容易。但是如果需要获取上传的文件,就必须使用Request对象的BinaryRead方法来读取。BinaryRead方法是对当前输入流进行指定字节数的二进制读取,有点需要注意的是,一旦使用BinaryRead 方法后,再也不能使用Request.Form 或 Request.QueryString 集合了。结合Request对象的TotalBytes属性,可以将所有表单提交的数据全部变成二进制,不过这些数据都是经过编码的。首先让我们来看看这些数据是如何编码的,有无什么规律可循,编段代码,在代码中我们将BinaryRead读取的二进制转化为文本,输出出来,在后台的upload.asp中(注意该示例不要上传大文件,否则可能会造成浏览器死掉):
    <%
    Dim biData, PostData
    Size = Request.TotalBytes
    biData = Request.BinaryRead(Size)
    PostData = BinaryToString(biData,Size)
    Response.Write "<pre>" & PostData & "</pre>"  '使用pre,原样输出格式
    ' 借助RecordSet将二进制流转化成文本
    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
    %>


    简单起见,上传一个最简单的文本文件(G:\homepage.txt,内容为"宝玉:http://www.webuc.net")来试验一下,文本框filename中保留默认值"default filename",提交看看输出结果:

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

    可以看出来对于表单中的项目,是用过"-----------------------------7d429871607fe"这样的边界来分隔成一块一块的,每一块的开始都有一些描述信息,例如:Content-Disposition: form-data; name="filename",在描述信息中,通过name="filename"可以知道表单项的name。如果有filename="G:\homepage.txt"这样的内容,说明是一个上传的文件,如果是一个上传的文件,那么描述信息会多一行Content-Type: text/plain来描述文件的Content-Type。描述信息和主体信息之间是通过换行来分隔的。

    嗯,基本上清晰了,根据这个规律我们就知道该怎么来分离数据,再对分离的数据进行处理了,不过差点忽略一个问题,就是边界值(上例中的"-----------------------------7d429871607fe")是怎么知道的?每次上传这个边界值是不一样的,还好还好asp中可以通过Request.ServerVariables( "HTTP_CONTENT_TYPE")来获之,例如上例中HTTP_CONTENT_TYPE内容为:"multipart/form-data; boundary=---------------------------7d429871607fe",有了这个,我们不仅可以判断客户端的form中有无使用enctype="multipart/form-data"(如果没有使用,那么下面就没必要执行啦),还可以获取边界值boundary=---------------------------7d429871607fe。(注意:这里获取的边界值比上面的边界值开头要少"--",最好补充上。)

    至于如何分析数据的过程我就不多赘述了,无非就是借助InStr,Mid等这样的函数来分离出来我们想要的数据。

    二、分块上传,记录进度
    要实时反映进度条,实质就是要实时知道当前服务器获取了多少数据?再回想一下我们实现上传的过程,我们是通过Request.BinaryRead(Request.TotalBytes)来实现的,在Request的过程中我们无法得知当前服务器获取了多少数据。所以只能通过变通的方法了,如果我们可以将获取的数据分成一块一块的,然后根据已经上传的块数我们就可以算出来当前上传了多大了!也就是说,如果我1K为1块,那么上传1MB的输入流就分成1024块来获取,例如我当前已经获取了100块,那么就表明当前上传了100K。当我提出分块的时候很多人觉得不可思议,因为他们都忽略BinaryRead方法不仅是可以读取指定大小,而且可以连续读取的。

    写个例子来验证一下分块读取的完整性,在刚才的例子基础上(注意该示例不要上传大文件,否则可能会造成浏览器死掉):

    <%
    Dim biData, PostData, TotalBytes, ChunkBytes
    ChunkBytes = 1 * 1024     ' 分块大小为1K
    TotalBytes = Request.TotalBytes  ' 总大小
    PostData = ""         ' 转化为文本类型后的数据
    ReadedBytes = 0        ' 初始化为0
    ' 分块读取
    Do While ReadedBytes < TotalBytes
     biData = Request.BinaryRead(ChunkBytes)  ' 当前块
     PostData = PostData & BinaryToString(biData,ChunkBytes) ' 将当前块转化为文本并拼接
     ReadedBytes = ReadedBytes + ChunkBytes ' 记录已读大小
     If ReadedBytes > TotalBytes Then ReadedBytes = TotalBytes
    Loop
    Response.Write "<pre>" & PostData & "</pre>"  ' 使用pre,原样输出格式
    ' 将二进制流转化成文本
    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
    %>

    试验一下上传刚才的文本文件,输出结果证明这样分块读取的内容是完整的,并且在While循环中,我们可以在每次循环时将当前状态记录到Application中,然后我们就可以通过访问该Application动态获取上传进度条。

    另:上例中是通过字符串拼接的,如果是要拼接二进制数据,可以通过ADODB.Stream对象的Write方法,示例代码如下:

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


    三、保存上传的文件
    通过Request.BinaryRead获取提交数据,分离出上传文件后,根据数据类型的不同,保存方式也不同:

    对于二进制数据,可以直接通过ADODB.Stream对象的SaveToFile方法,将二进制流保存成为文件。
    对于文本数据,可以通过TextStream对象的Write方法,将文本数据保存到文件中。
    对于文本数据和二进制数据,是可以方便的相互转换的,对于上传小文件来说,两者基本上没什么差别。但是两种方式保存时还是有一些差别的,对于ADODB.Stream对象,必须将所有数据全部装载完才可以保存成文件,所以使用这种方式如果上传大文件将很占用内存,而对于TextStream对象,可以在文件创建好后,一次Write一部分,分多次Write,这样的好处是不会占用服务器内存空间,结合上面分析的分块获取数据原理,我们可以每获取一块上传数据就将之Write到文件中。我曾做过试验,同样本机上传一个200多MB的文件,使用第一种方式内存一直在涨,到最后直接提示计算机虚拟内存不足,最可恨是即使进度条表示文件已经上传完,但是最终文件还是没有保存上。而使用后一种方法,上传过程中内存基本上无什么变化。

    四、未解决的难题
    我在博客园上看到Bestcomy描述他的Asp.Net上传组件是可以和Sever.SetTimeOut无关的,而在Asp中我是没能做到,对于上传大文件,就只有将Server.SetTimeOut设置为一个很大的值才可以。不知道有没有比较好的解决方法。

    如果我们在保存文件时,使用TextStream对象的Write方法,那么如果用户上传时中断了文件传输,已经上传的那部分文件还是在的,如果可以断点续传就好了。关键问题是Request.BinaryRead方法虽然可以分块读取,但是却不能跳过某一段读取!

    五、结束语
    原理基本上是说清楚了,但是实际代码要比这复杂的多,要考虑很多问题,最麻烦在分析数据那部分,对于每一块获取的数据,要分析是不是属于描述信息,是表单项目还是上传的文件,文件是否已经上传结束……

    相信根据上面的描述,您也可以开发出您自己功能强大的无组件上传组件。我想更多的人关心的只是代码,而不会自己动手去写的,也许没有时间,也许水平还不够,更多的只是已经成为了一种习惯……我在CSDN上见过太多技术八股文——一段说明,然后全是代码。授人以鱼不若授人以渔,给你一个代码,也许你并不会去思考为什么,直接拿去用,当下次碰到类似的问题的时候,还是不知道为什么,希望此文能让更多人学到点什么,最重要是“悟”到点什么!

    发表于 @ 2004年10月15日 16:30:00|评论(loading...)|编辑

    新一篇: oracle sql总结 | 旧一篇: ORACLE PL/SQL 基础2 (游标的学习)

    评论

    # 发表于2004-10-25 09:42:00  IP:
    TrackBack来自《测试trackback》

    不知道怎么搞的
    #乾坤一笑 发表于2004-10-25 09:56:00  IP:
    TrackBack来自《》

    Ping Back来自:blog.csdn.net
    #乾坤一笑 发表于2004-10-25 09:57:00  IP:
    TrackBack来自《》

    Ping Back来自:blog.csdn.net
    #999 发表于2004-11-07 14:20:00  IP: 220.163.35.*
    基于asp无组件上传技术实现的文件管理软件,功能强大

    http://www.blue999.com/webfiles/index.htm
    #12432 发表于2004-11-19 16:23:00  IP: 222.222.61.*
    423423
    #111111111111111 发表于2004-11-19 16:23:00  IP: 222.222.61.*
    111111111111111111111111
    #discovery 发表于2005-01-21 10:02:00  IP: 202.102.50.*
    写得很好,谢谢宝玉BLOG。
    授人以鱼不若授人以渔,说得太好了。。。网上确实有许多技术八股文——一段说明,然后全是代码,让人看得莫名其秒,对于我们这些新手来说,更是被挡在了这些技术的门外。。。
    #阿福 发表于2005-04-17 22:53:00  IP: 222.37.0.*
    我看不懂也!有没有简单一点的呀!
    我是个新手!我只回做新闻系统
    就是不回无组件上传也!
    麻烦了也!!我不希望被当在技术的门外呀!!
    我的邮箱是:wrafu@163.com
    #Kyori 发表于2005-04-18 20:22:00  IP: 218.27.70.*
    好东西,收藏~
    #w 发表于2005-04-26 14:02:00  IP: 61.185.212.*
    看不懂 
    #cherry 发表于2005-12-04 00:00:00  IP: 61.186.97.*
    为什么我执行不能处理中文呢???
    #过路 发表于2006-07-25 15:50:00  IP: 220.115.20.*
    谢谢你的发表
    我们就是需要多一些这样的技术文章
    踏踏实实搞清道理
    #studi 发表于2006-07-31 16:54:00  IP: 211.69.205.*
    写得太好了.我喜欢分析原理的文章.
    代码要是一个地方出错就和乱码差不多.
    #dsaf 发表于2006-08-30 13:52:00  IP: 218.65.242.*
    dsafdasgf
    #jun 发表于2006-09-04 08:46:00  IP: 218.7.30.*
    还可以
    #飞鸟 发表于2006-10-20 15:23:00  IP: 218.14.89.*
    很好,支持,
    #cp 发表于2006-12-01 16:54:00  IP: 59.40.41.*
    有整个的源码没有
    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © 小力力力