• FLEX+Webservice 大附件上传、断点续传实现


    客户端最近项目需要,面临大附件上传的功能,具体研究如下:
    实现思路
    大附件上传,如何流畅不占用内存,还要支持断点续传,当第一次看到这些需求的时候还是有所顾虑,传统ASP.NET中利用fileupload可以实现上传,但是webconfig中文件大小受限制,即使设置大小了也将面临超时的问题。对于上述情况,WINFORM应该能够很好的解决断点续传大文件,当应用到WEB应用中的时候就很难如此轻松了,因此富客户端思想是很好的选择,决定采用FLEX实现客户端,Webservice实现服务端。
    由于ASP.NET默认支持4M大小文件上传,一次需要将需要上传的文件进行分割,客户端分块上传,服务端分块追加。
    具体实现
    1)、客户端实现

      客户端界面设计

    <s:Group  width="100%" height="100%">
            
    <s:Button id="btnBrower" x="390" y="25" label="浏览..." width="60" click="btnBrower_clickHandler(event)"></s:Button>
            
    <s:TextInput id="edFile" x="21" y="24" width="361" enabled="false"/>
            
    <s:Button id="btnUpload" x="458" y="25" label="开始上传" width="71" click="btnUpload_clickHandler(event)"/>
            
    <mx:Canvas width="508" height="25" backgroundColor="0Xf1f1f1" x="21" y="53" borderStyle="solid" borderColor="0Xbbbbbb">
                
    <mx:Label text="" fontWeight="bold" id="tip_txt" x="5" y="4"/>            
            
    </mx:Canvas>
            
    <mx:Canvas id="totalProcess" borderStyle="solid" x="22" width="507" y="82" height="13" borderColor="0X124fc0" backgroundColor="0xffffff">
                
    <mx:Canvas backgroundColor="0X124fc0" backgroundAlpha="0.5" id="processBar_Total" width="0" height="23"/>
            
    </mx:Canvas>
            
        
    </s:Group>


      定义Webservice方法,对应服务端,各自有自己的返回事件

    <s:WebService id="service" wsdl="../Service.asmx?wsdl" useProxy="false">
                
    <s:operation name="WriteFile" result="onResult(event)" fault="onFault(event)">                
                
    </s:operation>
                
    <s:operation name="CheckFile" result="onCheckResult(event)" fault="onCheckFault(event)">                
                
    </s:operation>            
                
    <s:operation name="CopyFile" result="onCopyResult(event)" fault="onCopyFault(event)">                
                
    </s:operation>
            
    </s:WebService>

      浏览需要上传的文件

          //页面加载完毕,进行相关事件注册
                protected function application1_creationCompleteHandler(event:FlexEvent):void
                {
                    
    // 注册调用js函数
                    ExternalInterface.addCallback("getFileInfo",GetFileInfo);
                    
                    
    //初始化文件浏览事件
                    file.addEventListener(Event.SELECT,onSelect);//选择文件事件
                    file.addEventListener(Event.COMPLETE,onComplete);//文件加载完毕
                    file.addEventListener(Event.OPEN,onOpen);
                    btnUpload.enabled
    =false;
                }
                
                //浏览文件
                private function onSelect(evt:Event):void
                {
                    
    this.tip_txt.text="";    
                    edFile.text
    =file.name;
                    
    //浏览完成,开始加载
                    file.load();
                }
                
    //加载文件完毕
                private function onComplete(evt:Event):void
                {    
                    
    this.tip_txt.text="加载完毕";            
                    btnUpload.enabled
    =true;
                }
                
                private 
    function onOpen(evt:Event):void
                {
                    
    this.tip_txt.text="正在加载...";
                }


      校验服务端文件是否存在,不存在则创建,存在则判断是否需要断点续传

           //校验文件函数
                private function CheckFile():void
                {
                    
    //调用webservice方法,传递文件名进行校验
                    service.CheckFile.send(file.name);
                }
           
           //webervice,校验成功
                private function onCheckResult(event:ResultEvent):void
                {
                    
    //获取返回值
                    var retArray:Array=new Array();
                    retArray
    =event.result.toString().split(",");
                    
    var retMsg:String=retArray[0].toString();//返回文件存在与否消息
                    var retNum:int=int(retArray[1].toString());//返回文件大小                
                    tip_txt.text=retMsg;
                    
                    
    //判断是否存在文件
                    if(retNum != 0)
                    {
                        
    //若文件已经存在,判断文件是否已经上传完毕
                        if(retNum == file.data.length)
                            tip_txt.text
    ="文件已上传完毕";
                        
    else
                        {
                            tip_txt.text
    ="准备断点续传";
                            
                            
    //断点续传需要重新计算块数,剩余大小
                            var Leave:int= file.data.length-retNum;
                            
                            
    //判断剩余情况
                            if(Leave>blocksize)
                            {
                                
    //剩余部分分块    
                                var BlockNum2:Number=(Leave / blocksize);
                                BlockNum
    =int(BlockNum2);
                                BlockNumles
    =int(BlockNum2);
                                reBlock
    =Leave % blocksize;                            
                                tip_txt.text
    ="正在处理...";
                                
    //调用上传函数
                                uploadFile(retNum,blocksize);                            
                            }
                            
    else
                            {
                                
    //直接从返回值大小开始,传递剩余部分
                                BlockNumles=1;
                                uploadFile(retNum,reBlock);
                            }                                    
                        }
                    }
                    
    else
                    {
                        
    //若文件不存在,则创建,从0开始
                        var BlockNum1:Number=(file.data.length / blocksize);
                        BlockNum
    =int(BlockNum1);
                        BlockNumles
    =int(BlockNum1);
                        reBlock
    =file.data.length % blocksize;
                        
                        tip_txt.text
    ="正在处理...";    
                        uploadFile(retNum,blocksize);
                    }                
                }
                
                private 
    function onCheckFault(event:FaultEvent):void
                {
                    Alert.show(event.toString());
                }
                
               


      开始上传

            //上传附件函数
                private function uploadFile(begin:int,end:int):void
                {                
                    
    //判断文件大小
                    if(file.data.length>blocksize)
                    {
                        
    //读取部分文件,分块上传
                        fileUpload.writeBytes(file.data,begin,end);
                        service.WriteFile.send(file.name,fileUpload);
                    }
                    
    else
                    {                    
                        
    //直接上传
                        service.WriteFile.send(file.name,fileUpload);
                    }                                                
                }

          //webservice相关事件函数,上传成功
                private function onResult(event:ResultEvent):void
                {
                    
    //每次上传成功返回值,作为下次传递的开始位置
                    var begin:int=int(event.result.toString());
                    BlockNumles
    -=1;//递减
                    BlockNumadd+=1;//递增
                    
    //清空历史数据
                    fileUpload.clear();
                    
                    
    //进度条
                    onProgress(begin,file.data.length);
                    
    //判断剩余块多少,进行不同情况的上传
                    if(BlockNumles>0)
                    {
                        uploadFile(begin,blocksize);
                    }
                    
                    
    if(BlockNumles==0)
                    {
                        uploadFile(begin,file.data.length
    -begin);
                        tip_txt.text
    ="上传完毕!";
                        tip_txt.text
    ="开始扫描文件...";
                        service.CopyFile.send(file.name);
                    }                
                }
                
    //上传失败
                private function onFault(event:FaultEvent):void
                {
                    Alert.show(
    event.toString());
                }

    进度监视

    //上传进度条
                private function onProgress(Loaded:int,Total:int):void
                {
                    processBar_Total.width
    =(Loaded/Total)*506;                
                    tip_txt.text
    ="已上传:" + Loaded+'/'+Total;
                    
    if(Loaded==Total)
                        tip_txt.text
    ="已上传完毕";
                }    


      上传完毕处理文件,完毕之后需要对文件进行类似处理,在这里是对文件进行重命名。具体在客户端可以体现出来

    //复制文件
                private function onCopyResult(event:ResultEvent):void
                {
                    tip_txt.text
    ="扫描完成";
                    
    //文件上传结束,调用js函数
                    var f:String = "showButton";
                    var m:String 
    = ExternalInterface.call(f);
                    trace(m); 
                }
                
                
    private function onCopyFault(event:FaultEvent):void
                {
                    Alert.show(
    event.toString());
                }

    2)、服务端实现
      对应客户端三个方法实现,分别是校验、上传、上传完毕
      校验文件,并返回值

        #region 校验文件是否存在
        [WebMethod]
        
    public string CheckFile(string FileName)
        {
            
    string FileSavePath = Server.MapPath("File/"+ FileName;
            
    if (!IsExistFile(FileSavePath))
                
    return "文件不存在,0";
            
    else
            {
                
    string FileSize = GetFileSize(FileSavePath).ToString();
                
    return "文件已存在," + FileSize;
            }
        }
        
    #endregion


      开始写文件,没有则创建,有则追加

        #region 写文件
        [WebMethod]
        
    public string WriteFile(string FileName, byte[] filestrem)
        {
            
    string FileSavePath = Server.MapPath("File/"+ FileName + ".temp";
            
    if (!IsExistFile(FileSavePath))
            {
                FileStream fs 
    = new FileStream(FileSavePath, FileMode.Create);
                
    //获得字节数组
                byte[] data = filestrem;
                
    //开始写入
                fs.Write(data, 0, data.Length);
                
    //清空缓冲区、关闭流
                fs.Flush();
                fs.Close();
            }
            
    else
            {
                
    //追加文件
                using (System.IO.FileStream f = new System.IO.FileStream(FileSavePath, System.IO.FileMode.Append, FileAccess.Write))
                {
                    
    byte[] b = filestrem;
                    f.Write(b, 
    0, b.Length);
                }
            }

            
    return GetFileSize(FileSavePath).ToString();
        }
        
    #endregion


      上传完毕

    #region
        [WebMethod]
        
    public string CopyFile(string FileName)
        {
            
    string FileSavePath = Server.MapPath("File/"+ FileName+".temp";
            
    string FileConvertPath = Server.MapPath("ConvertFile/"+ FileName;

            
    //如果目标中存在同名文件,则删除   
            if (IsExistFile(FileConvertPath))
            {
                DeleteFile(FileConvertPath);
            }
            
    //将文件复制到指定目录   
            File.Copy(FileSavePath, FileConvertPath);

            
    //删除原始临时文件
            DeleteFile(FileSavePath);

            
    string Path = FileConvertPath;
            
    return Path;
        }
        
    #endregion


    存在问题
    客户端要把文件读取完毕之后,才开始分段上传,如果文件过大,内存玩儿不转那么浏览器将会死掉。需要继续改进,请大家拍砖!!源代码全部奉上,了解flex的可以看看flex部分源码,不了解的可以直接在项目中使用,已经在.NET项目中配置完毕,可直接运行看到效果。本例子仅为beta1.0版本,还在继续修改当中。

    效果图:

    源码:断点续传Server.rar  客户端


     

  • 相关阅读:
    关于软件设计中遇到的问题
    关于power shell
    如果TChart的发生异常
    重温gof版《设计模式》中的创建型模式
    如何更好的使用cvs
    存储过程返回临时表的问题
    关于bugzilla与svn结合的配置注意事项
    VC知识点:如何用vc6调试CGI程序
    如何让应用程序托盘化
    符号表
  • 原文地址:https://www.cnblogs.com/tzy080112/p/2169173.html
Copyright © 2020-2023  润新知