我想用spcomm来传递文件,不知道怎么传递,请问有谁知道不

解决方案 »

  1.   

    spcomm一般用來實現串口通信或與其它設備接口(如:單片機),用來傳遞文件還沒有研究過;可以參考一下其它組件或方法,如下:
    1.基於TCP或UDP通訊方式(C/S);
    2.VPN或自己做中轉
    以下提供一個UDP方式的網絡傳輸,UDP較快...客户端;   
        
      unit   U_Client;   
        
      interface   
        
      uses   
          Windows,   Messages,   SysUtils,   Variants,   Classes,   Graphics,   Controls,   Forms,   
          Dialogs,   IdBaseComponent,   IdComponent,   IdTCPConnection,   IdTCPClient,   Math,   
          StdCtrls,   ComCtrls,   IdUDPBase,   IdUDPServer,   IdSocketHandle;   
        
      const   
      mtFUDPDirReq   =   8000;   
      mtFUDPDirACK   =   9000;   
      mtFUDPReq   =   8001;   
      mtFUDPACK   =   9001;   
      mtFUDPDataReq   =   8002;   
      mtFUDPDataACK   =   9002;   
        
      type   
      rMsgHead   =   record   
      MsgType:   integer;   
      Userid   :   array[0..20]   of   Char;   
      DataSize:   WORD;//0~65535   
      end;   
        
      rFUDPReq   =   record   
      ReqType:   BYTE;//setup:   1/   stop:   2/   finish:   3   
      end;   
        
      rFUDPACK   =   record   
      lResult:   BYTE;//ack:   1/   unknown:   0   
      FileName:   array[0..64]   of   char;   
      FileSize:   integer;   
      end;   
        
      rFUDPDataReq   =   record   
      FUDPId:   WORD;   
      FileName:   array[0..64]   of   char;   
      StartPos:   integer;   
      Length:       WORD;   
      end;   
        
      rFUDPDataACK   =   record   
      FUDPId:   WORD;   
      Length:   WORD;   
      PieceBuf:   array[0..1024]   of   char;   
      end;   
        
      rFUDPReqBag   =   record   
      Head:   rMsgHead;   
      Data:   rFUDPReq;   
      end;   
        
      rFUDPACKBag   =   record   
      Head:   rMsgHead;   
      Data:   rFUDPACK;   
      end;   
        
      rFUDPDataReqBag   =   record   
      Head:   rMsgHead;   
      Data:   rFUDPDataReq;   
      end;   
        
      rFUDPDataACKBag   =   record   
      Head:   rMsgHead;   
      Data:   rFUDPDataACK;   
      end;   
        
          Tfrm_Client   =   class(TForm)   
        SaveDialog1:   TSaveDialog;   
        IdTCPClient1:   TIdTCPClient;   
        Button1:   TButton;   
        StatusBar1:   TStatusBar;   
        Edit1:   TEdit;   
        Label1:   TLabel;   
              Edit2:   TEdit;   
              Label2:   TLabel;   
        ClientUDP:   TIdUDPServer;   
      //   procedure   Button1Click(Sender:   TObject);   
        procedure   FormCreate(Sender:   TObject);   
        procedure   Button1Click(Sender:   TObject);   
        procedure   ClientUDPUDPRead(Sender:   TObject;   AData:   TStream;   
      ABinding:   TIdSocketHandle);   
          private         {   Private   declarations   }   
          public           {   Public   declarations   }   
          end;   
        
      var   
      frm_Client:   Tfrm_Client;   
      ASize,   TotalSize:   integer;   
      AFileStream:   TFileStream;   
      RecvBit:   BYTE;   
        
      implementation{$R   *.dfm}   
        
      {procedure   Tfrm_Client.Button1Click(Sender:   TObject);   
      var   
          cmd:   string;   
          ASize,   TotalSize:   Int64;   
          AFileStream:   TFileStream;   
      begin   
          IdTCPClient1.Host   :=   Edit1.Text;   //连接主机   
          IdTCPClient1.Port   :=   StrToIntDef(Edit2.Text,   9925);   //端口   
          IdTCPClient1.Connect;   //连接   
          try   
        IdTCPClient1.WriteLn('BEGIN');   //提示服务器开始接收   
        cmd   :=   IdTCPClient1.ReadLn;   
        //以“|”符号分离文件名   
        SaveDialog1.FileName   :=   Copy(cmd,   Pos('|',   cmd)   +   1,   Length(cmd));   
        if   not   SaveDialog1.Execute   then   begin   
      IdTCPClient1.WriteLn('CANCEL');   //告诉服务器取消   
      IdTCPClient1.Disconnect;   //断开连接   
      exit;   
        end;   
        TotalSize   :=   StrToInt(Copy(cmd,   0,   Pos('|',   cmd)   -   1));   //分离文件大小   
        //建立文件流准备接收   
        AFileStream   :=   TFileStream.Create(SaveDialog1.FileName,   fmCreate);   
        try   //循环开始接受   
      repeat   
          IdTCPClient1.WriteLn(IntToStr(AFileStream.Size));//发送当前传输的位置   
          ASize   :=   Min(TotalSize   -   AFileStream.Size,   IdTCPClient1.RecvBufferSize);   
          //选择剩余大小和缓冲区大小小的一个作为传输的大小   
          IdTCPClient1.ReadStream(AFileStream,   ASize);   //接收流   
          StatusBar1.SimpleText   :=   Format('当前传输位置%d/大小%d',   [AFileStream.Size,   TotalSize]);   
          Application.ProcessMessages;   
      until   AFileStream.Size   =   TotalSize;   //大小一致了表示结束   
        finally   
      AFileStream.Free;   //释放文件流   
        end;   
        IdTCPClient1.WriteLn('END');   //提示服务器传输完成   
        StatusBar1.SimpleText   :=   '传输完成...';   
          except   
        StatusBar1.SimpleText   :=   '连接服务器失败或者对方已经中断传输!';   
          end;   
          IdTCPClient1.Disconnect;   
      end;}   
        
      procedure   Tfrm_Client.FormCreate(Sender:   TObject);   
      begin   
      try   
      ClientUDP.DefaultPort:=6061;   
      ClientUDP.Active   :=true;   
      StatusBar1.SimpleText   :=   Format('运行端口:[%d]',   [6061]);   
      except   
      on   EIdCouldNotBindSocket   do   begin   
      StatusBar1.SimpleText   :=   '侦听失败!';   
      end;   
      end;   
      end;   
        
      procedure   Tfrm_Client.Button1Click(Sender:   TObject);   
      var   
      FUDPReq:   rFUDPReqBag;   
      begin   
      FUDPReq.Head.MsgType:=mtFUDPReq;   
      StrPCopy(FUDPReq.Head.Userid,   '');   
      FUDPReq.Head.DataSize:=0;   
      FUDPReq.Data.ReqType:=1;   
      ClientUDP.SendBuffer('127.0.0.1',   6062,   FUDPReq,   SizeOf(rFUDPReqBag));   
      AFileStream:=nil;   
      ASize:=0;   
      end;   
        
      procedure   Tfrm_Client.ClientUDPUDPRead(Sender:   TObject;   AData:   TStream;   
          ABinding:   TIdSocketHandle);   
      var   
      _UDPHead:   rMsgHead;   
      _FUDPACK:   rFUDPACK;   
      _FUDPDataACK:   rFUDPDataACK;   
      FUDPDataReq:   rFUDPDataReqBag;   
      FUDPReq:   rFUDPReqBag;   
      MsgType:integer;   
      begin   
      try   
      AData.Read   (_UDPHead,sizeof(_UDPHead)   );     //接收数据头   
      MsgType:=_UDPHead.MsgType;   
      if   Msgtype=-1   then   exit;   
      case     MsgType   of   
      mtFUDPACK   :   begin   
      Adata.Read(_FUDPACK,   SizeOf(rFUDPACK));   
      SaveDialog1.FileName   :=   _FUDPACK.FileName;   
      if   not   SaveDialog1.Execute   then   begin   
      ShowMessage('This   operation   cancels   the   file   download.');   
      end;   
      TotalSize   :=   _FUDPACK.FileSize;   
      AFileStream   :=   TFileStream.Create(SaveDialog1.FileName,   fmCreate);   
      ASize:=0;   
      try   //循环开始接受   
      Application.ProcessMessages;   
      FUDPDataReq.Head.MsgType:=mtFUDPDataReq;   
      StrPCopy(FUDPDataReq.Head.Userid,   '');   
      FUDPDataReq.Head.DataSize:=0;   
      FUDPDataReq.Data.FUDPId:=mtFUDPDataReq;   
      StrPCopy(FUDPDataReq.Data.FileName,   _FUDPACK.FileName);   
      FUDPDataReq.Data.StartPos:=ASize;   
      FUDPDataReq.Data.Length:=Min(1024,   TotalSize-ASize);   
      StatusBar1.SimpleText   :=   Format('Current   transfer   position:   %d/Size:   %d',   [ASize,   TotalSize]);   
      ClientUDP.SendBuffer('127.0.0.1',   6062,   FUDPDataReq,   SizeOf(rFUDPDataReqBag));   
      except   
      AFileStream.Free;   //释放文件流   
      end;   
      end;   
        
      mtFUDPDataACK:   begin   
      Adata.Read(_FUDPDataACK,   SizeOf(rFUDPDataACK));   
      if   AFileStream<>nil   then   begin   
      AFileStream.Position:=ASize;   
      AFileStream.WriteBuffer(_FUDPDataACK.PieceBuf,   _FUDPDataACK.Length);   
      ASize:=ASize+_FUDPDataACK.Length;   
      if   ASize<TotalSize   then   begin   
      try   //循环开始接受   
      Application.ProcessMessages;   
      FUDPDataReq.Head.MsgType:=mtFUDPDataReq;   
      StrPCopy(FUDPDataReq.Head.Userid,   '');   
      FUDPDataReq.Head.DataSize:=0;   
      FUDPDataReq.Data.FUDPId:=mtFUDPDataReq;   
      StrPCopy(FUDPDataReq.Data.FileName,   _FUDPACK.FileName);   
      FUDPDataReq.Data.StartPos:=ASize;   
      FUDPDataReq.Data.Length:=Min(1024,   TotalSize-ASize);   
      StatusBar1.SimpleText   :=   Format('Current   transfer   position:   %d/Size:   %d',   [ASize,   TotalSize]);   
      ClientUDP.SendBuffer('127.0.0.1',   6062,   FUDPDataReq,   SizeOf(rFUDPDataReqBag));   
      except   
      AFileStream.Free;   //释放文件流   
      end;   
      end   else   begin   
      FUDPReq.Head.MsgType:=mtFUDPReq;   
      StrPCopy(FUDPReq.Head.Userid,   '');   
      FUDPReq.Head.DataSize:=0;   
      FUDPReq.Data.ReqType:=3;   
      ClientUDP.SendBuffer('127.0.0.1',   6062,   FUDPReq,   SizeOf(rFUDPReqBag));   
      StatusBar1.SimpleText   :=   'File   transfer   finished...';   
      AFileStream.Free;   //释放文件流   
      end;   
      end;   
      end;   
      end;   
      except   on   E:Exception   do   
      ShowMessage(E.Message);   
      end;   
      end;   
        
      end.  
     
      

  2.   

    服务器端:   
      
    unit   U_Server;   
        
      interface   
        
      uses   
          Windows,   Messages,   SysUtils,   Variants,   Classes,   Graphics,   Controls,   Forms,   
          Dialogs,   StdCtrls,   ComCtrls,   IdBaseComponent,   IdComponent,   IdTCPServer,   Math,   
          IdUDPBase,   IdUDPServer,   IdSocketHandle;   
        
      const   
      mtFUDPDirReq   =   8000;   
      mtFUDPDirACK   =   9000;   
      mtFUDPReq   =   8001;   
      mtFUDPACK   =   9001;   
      mtFUDPDataReq   =   8002;   
      mtFUDPDataACK   =   9002;   
        
      type   
      rMsgHead   =   record   
      MsgType:   integer;   
      Userid   :   array[0..20]   of   Char;   
      DataSize:   WORD;//0~65535   
      end;   
        
      rFUDPReq   =   record   
      ReqType:   BYTE;//setup:   1/   stop:   2/   finish:   3   
      end;   
        
      rFUDPACK   =   record   
      lResult:   BYTE;//ack:   1/   unknown:   0   
      FileName:   array[0..64]   of   char;   
      FileSize:   integer;   
      end;   
        
      rFUDPDataReq   =   record   
      FUDPId:   WORD;   
      FileName:   array[0..64]   of   char;   
      StartPos:   integer;   
      Length:       WORD;   
      end;   
        
      rFUDPDataACK   =   record   
      FUDPId:   WORD;   
      Length:   WORD;   
      PieceBuf:   array[0..1024]   of   char;   
      end;   
        
      rFUDPReqBag   =   record   
      Head:   rMsgHead;   
      Data:   rFUDPReq;   
      end;   
        
      rFUDPACKBag   =   record   
      Head:   rMsgHead;   
      Data:   rFUDPACK;   
      end;   
        
      rFUDPDataReqBag   =   record   
      Head:   rMsgHead;   
      Data:   rFUDPDataReq;   
      end;   
        
      rFUDPDataACKBag   =   record   
      Head:   rMsgHead;   
      Data:   rFUDPDataACK;   
      end;   
        
          Tfrm_Server   =   class(TForm)   
        IdTCPServer1:   TIdTCPServer;   
        Button1:   TButton;   
        Button2:   TButton;   
        Button3:   TButton;   
        ProgressBar1:   TProgressBar;   
        StatusBar1:   TStatusBar;   
        Edit1:   TEdit;   
        Button4:   TButton;   
        OpenDialog1:   TOpenDialog;   
        Edit2:   TEdit;   
        Label1:   TLabel;   
        Label2:   TLabel;   
        ClientUDP:   TIdUDPServer;   
        procedure   Button1Click(Sender:   TObject);   
        procedure   Button4Click(Sender:   TObject);   
        procedure   Button2Click(Sender:   TObject);   
        procedure   Button3Click(Sender:   TObject);   
        procedure   IdTCPServer1Execute(AThread:   TIdPeerThread);   
        procedure   FormClose(Sender:   TObject;   var   Action:   TCloseAction);   
        procedure   FormCreate(Sender:   TObject);   
              procedure   ClientUDPUDPRead(Sender:   TObject;   AData:   TStream;   
                  ABinding:   TIdSocketHandle);   
          private{   Private   declarations   }   
        AFileStream:   TFileStream;   //传输的文件流   
        procedure   ButtonBegin;   
        procedure   ButtonEnd;   
          public         {   Public   declarations   }   
          end;   
        
      var   
          frm_Server:   Tfrm_Server;   
        
      implementation{$R   *.dfm}   
        
      procedure   Tfrm_Server.Button1Click(Sender:   TObject);   
      begin   
          if   OpenDialog1.Execute   then   
        Edit1.Text   :=   OpenDialog1.FileName;   
          if   not   FileExists(Edit1.Text)   then   begin//检测文件是否存在   
              Showmessage('文件不存在,请选择文件!');   
        exit;   
          end;   
          //建立文件流   
          AFileStream   :=   TFileStream.Create(Edit1.Text,   fmOpenRead);   
          ProgressBar1.Max   :=   AFileStream.Size;   
          ProgressBar1.Position   :=   0;   
          ButtonBegin;   //VCL开始状态设置   
      end;   
        
      procedure   Tfrm_Server.Button4Click(Sender:   TObject);   
      begin   
          Close;   
      end;   
        
      procedure   Tfrm_Server.Button2Click(Sender:   TObject);   
      begin   
          //服务器准备好连接   
      //     IdTCPServer1.DefaultPort   :=   StrToIntDef(Edit2.Text,   9925);   
      //     if   not   IdTCPServer1.Active   then   IdTCPServer1.Active   :=   True;   
      end;   
        
      procedure   Tfrm_Server.ButtonBegin;   
      begin   //VCL开始状态设置   
          Button1.Enabled   :=   False;   
          Button2.Enabled   :=   False;   
          Button3.Enabled   :=   True;   
          Button4.Enabled   :=   False;   
      end;   
        
      procedure   Tfrm_Server.ButtonEnd;   
      begin   //VCL结束状态设置   
          Button1.Enabled   :=   True;   
          Button2.Enabled   :=   True;   
          Button3.Enabled   :=   False;   
          Button4.Enabled   :=   True;   
      end;   
        
      procedure   Tfrm_Server.Button3Click(Sender:   TObject);   
      begin   
          StatusBar1.SimpleText   :=   '传输取消...';   
          AFileStream.Free;   //释放文件流   
          ButtonEnd;   //VCL结束状态设置   
      end;   
        
      procedure   Tfrm_Server.IdTCPServer1Execute(AThread:   TIdPeerThread);   
      var   
          cmd:   string;   //接收到客户端的字符串信息   
          ASize:   Integer;   //需要传输的流大小   
      begin   
          with   AThread.Connection   do   begin//已经连街上的一个进程   
        cmd   :=   UpperCase(ReadLn);   //客户端发送的命令字符串   
        if   cmd   =   'BEGIN'   then   begin//开始传输   
      //告诉远程传输文件的大小和文件名   
      WriteLn(Format('%d|%s',   [AFileStream.Size,   ExtractFileName(Edit1.Text)]));   
      StatusBar1.SimpleText   :=   '准备传输...';   
      Exit;   
        end;   
        if   cmd   =   'END'   then   begin   //传输完成   
      Button3.Click;   
      StatusBar1.SimpleText   :=   '传输完成...';   
      Exit;   
        end;   
        if   cmd   =   'CANCEL'   then   begin   //传输取消   
      StatusBar1.SimpleText   :=   '传输取消...';   
      //保持传输状态   
      Exit;   
        end;   
        //按照指定位置传输文件   
        AFileStream.Seek(StrToInT(cmd),   soFromBeginning);   //转到文件流传输的位置   
              ASize   :=   Min(AFileStream.Size   -   AFileStream.Position,   RecvBufferSize);   
              //计算需要发送的大小,Min()函数在Math单元   
              OpenWriteBuffer;   //准备发送缓冲   
              WriteStream(AFileStream,   false,   false,   ASize);   
              //注意这个函数的参数。   
              CloseWriteBuffer;   //结束发送缓冲   
              StatusBar1.SimpleText   :=   Format('当前传输位置%s/大小%d',   [cmd,   AFileStream.Size]);   
        ProgressBar1.Position   :=   ProgressBar1.Position   +   ASize;   
          end;   
      end;   
        
      procedure   Tfrm_Server.FormClose(Sender:   TObject;   var   Action:   TCloseAction);   
      begin   
          IdTCPServer1.Active   :=   False;   
      end;   
        
      procedure   Tfrm_Server.FormCreate(Sender:   TObject);   
      begin   
      try   
      ClientUDP.DefaultPort:=6062;   
      ClientUDP.Active   :=true;   
      StatusBar1.SimpleText   :=   Format('运行端口:[%d]',   [6062]);   
      except   
      on   EIdCouldNotBindSocket   do   begin   
      StatusBar1.SimpleText   :=   '侦听失败!';   
      end;   
      end;   
      end;   
        
      procedure   Tfrm_Server.ClientUDPUDPRead(Sender:   TObject;   AData:   TStream;   
          ABinding:   TIdSocketHandle);   
      var   
      _UDPHead:   rMsgHead;   
      _FUDPReq:   rFUDPReq;   
      FUDPACK:   rFUDPACKBag;   
      _FUDPDataReq:   rFUDPDataReq;   
      FUDPDataACK:   rFUDPDataACKBag;   
      MsgType:integer;   
      //       ASize:   Integer;   //需要传输的流大小   
      begin   
      try   
      AData.Read   (_UDPHead,sizeof(_UDPHead)   );     //接收数据头   
      MsgType:=_UDPHead.MsgType;   
      if   Msgtype=-1   then   exit;   
      case     MsgType   of   
      mtFUDPReq   :   begin   
      Adata.Read(_FUDPReq,   SizeOf(rFUDPReq));   
      case   _FUDPReq.ReqType   of   
      1:   begin   
      FUDPACK.Head.MsgType:=mtFUDPACK;   
      StrPCopy(FUDPACK.Head.Userid,   '');   
      FUDPACK.Head.DataSize:=0;   
      FUDPACK.Data.lResult:=1;   
      StrPCopy(FUDPACK.Data.FileName,   ExtractFileName(Edit1.Text));   
      FUDPACK.Data.FileSize:=AFileStream.Size;   
      ClientUDP.SendBuffer('127.0.0.1',   6061,   FUDPACK,   SizeOf(rFUDPACKBag));   
      end;   
        
      2:   begin   
      end;   
        
      3:   begin   
      Button3.Click;   
      StatusBar1.SimpleText   :=   'File   transfer   finished...';   
      end;   
      end;   
      end;   
        
      mtFUDPDataReq:   begin   
      Adata.Read(_FUDPDataReq,   SizeOf(rFUDPDataReq));   
      //按照指定位置传输文件   
      AFileStream.Seek(_FUDPDataReq.StartPos,   0);   //转到文件流传输的位置   
      //ASize   :=   Min(AFileStream.Size   -   AFileStream.Position,   256);   
      //计算需要发送的大小,Min()函数在Math单元   
      FUDPDataACK.Head.MsgType:=mtFUDPDataACK;   
      StrPCopy(FUDPDataACK.Head.Userid,   '');   
      FUDPDataACK.Head.DataSize:=0;   
      FUDPDataACK.Data.FUDPId:=_FUDPDataReq.FUDPId;   
      FUDPDataACK.Data.Length:=_FUDPDataReq.Length;   
      AFileStream.ReadBuffer(FUDPDataACK.Data.PieceBuf,   _FUDPDataReq.Length);   
      try   
      ClientUDP.SendBuffer('127.0.0.1',   6061,   FUDPDataACK,   SizeOf(rFUDPDataACKBag));   
      except   
      ShowMessage('Error   in   read   file   to   buffer');   
      end;   
      StatusBar1.SimpleText   :=   Format('Current   transfer   position:   %d/size:   %d',   [_FUDPDataReq.StartPos,   AFileStream.Size]);   
      ProgressBar1.Position   :=   ProgressBar1.Position   +   _FUDPDataReq.Length;   
      end;   
      end;   
      except   on   E:Exception   do   
      ShowMessage(E.Message);   
      end;   
      end;   
        
      end.  
      

  3.   

    如果說真的想用spcomm組件來實現,那麼就切割、還原、傳送和接收方面要約定好規則,自己好好研究一下以下提供一些SPCOMM組件的屬性和方法,供參考http://topic.csdn.net/u/20080421/11/b2fbc209-cbbb-48ac-a6a2-e4847ec23b55.html?34190
      

  4.   

    用Spcomm的话,可以将文件以流的方式处理,就是发送方用一个循环读取并发送文件,接收方,收到数据后再还原成文件。
      

  5.   

    Spcomm不支持结构体的发送,所以传文件前先将文件信息以字符串形式发送,然后再将文件从流中读到一个动态byte数组里面,发送数组,发送完后再给个文件结束指令,对方收到文件结束指令后由byte数组写到TFileStream流中,于是就可以生成文件。大致思路就是这样的,新手写起来还是会出现一些错误的,比如文件接受不全,流指针错乱等,建议好好研究学习一下。如果你想直接要spcomm传任意大小文件并带传送进度条的代码,除非以前有人写过,在举手之劳的情况下可能会给你提供,否则,从零开始单独给你写这份代码,恐怕没有人去花这个精力。楼上朋友贴的代码是网络传文件的代码显示与楼主的问题不符。
      

  6.   

    非常感谢各位的热心解答,我听有别人说参考xmodem ymodem zmodem协议来传输文件,我对这个不熟悉,查了一下资料,很少,并且比较难理解,大家不知道熟悉这个不?
      

  7.   

    modem协议是很早时候的做法了
    熟悉的人肯定也不会多了还是自己简单制订一套机制好了