需要一个大于2G的带进度度的文件显示COPY代码,不希望用COPYFILE。。
求救!!!!!

解决方案 »

  1.   


    Function   CopyProgressRoutine(
        TotalFileSize   :   Int64;
        TotalBytesTransferred   :   Int64;
        StreamSize   :   Int64;
        StreamBytesTransferred   :   Int64;
        dwStreamNumber   :   Cardinal;
        dwCallbackReason   :   DWord;
        hSourceFile   :   THandle;
        hDestinationFile   :   THandle;
        lpData   :   Pointer):integer;Begin
          form1.ProgressBar1.Max:=StreamSize;
          form1.ProgressBar1.Min   :=0;
          form1.ProgressBar1.Position   :=   StreamBytesTransferred;
          application.ProcessMessages   ;
        Result   :=   PROGRESS_CONTINUE;
    end;{if   copyfileex(PChar(edt1.Text),PChar(edt2.text),
         @copyprogressroutine,
         nil,
         0,
         COPY_FILE_FAIL_IF_EXISTS)   then
    begin
    showmessage( 'COPY Success ');
    pb1.position:=0;
    end;
    }
      

  2.   

    if   copyfileex(PChar(edt1.Text),PChar(edt2.text),         //调用函数
         @copyprogressroutine,
         nil,
         0,
         COPY_FILE_FAIL_IF_EXISTS)   then
    begin
    showmessage( 'COPY Success ');
    pb1.position:=0;
    end;
      

  3.   

    不想用copyfileEX  这个代码效率有点低,是我现在用的,就是因为这个才求助的。。
      

  4.   

    如果单个大文件,copyfile应该也是最高效的了吧除非是需要复制到网络共享?压缩高的话,可以先压缩、复制、再解压缩
      

  5.   

    COPYFILE的效率是不错,但COPYFILEEX就不怎么样了,因为回调原因。。但因为文件太大,一般都大于2G所以,不给个提示还不行。。
      

  6.   

    俺感觉得这还不如copyfileex呢。
    如果是多个用户在copy,用copyifile传输怎么样效率都高不了,而如果是单独为某一个用户提供copy,那copyfileex的回调效率怎么也低不到能让用户察觉的程度。
      

  7.   

    系统应用是从服务器copy数据到本地,我最开始是用TfileStream,使用速度与效率都十分理想,但发现当文件超过2GB的时候有错误,于是用copyfile速度当然很快,但没有指示,后来就用copyfileEx,但这个效率有点低!
      

  8.   

    不用每次都在回调中刷新界面的.到达一定字节才刷新一次,这样就可以大大提高速度了.
    Type
      PCFPRData = ^TCFPRData;
      TCFPRData = record
        PB        : TProgressBar;
        Max       : Integer; //之所以不直接用TProgressBar来比较,看一下TProgressBar.GetMax就知道了
        Position  : Integer; //同上
      end;var
      bUserCancel : Boolean;Function CopyFilePR(TotalFileSize,TotalBytesTransferred,StreamSize,StreamBytesTransferred:Int64;
                        dwStreamNumber , dwCallbackReason : Cardinal;
                        hSourceFile , hDestinationFile : THandle;
                        Data : PCFPRData):DWORD; stdcall;
    var
      iPosition : integer;
    begin
      //40M以下的文件就不用显示进度条了,这里假设了复制速度在40M/秒以上,龟速复制不适合本回调
      if StreamSize<40*1024*1024 then begin
        Result := PROGRESS_QUIET;
        Exit;
      end;
      Result := PROGRESS_CONTINUE;  if Data.Max=0 then begin //只设置一次Max
        Data.Max    := StreamSize DIV (6*1024*1024); //48M/秒的复制速度,每秒跳动8次左右
        Data.PB.Max := Data.Max;
      end;
      iPosition := StreamBytesTransferred DIV (6*1024*1024);
      if iPosition<>Data.Position then begin //当需要同步进度条的时候才同步
        Data.Position := iPosition;
        Data.PB.Position := iPosition;
        Application.ProcessMessages; 
        //这里响应取消复制的操作
        if bUserCancel then Result := PROGRESS_CANCEL; //取消文件复制,并删除目标文件
      end;
    end;procedure TForm1.CancelBtnClick(Sender: TObject);
    begin
      bUserCancel := True;
    end;procedure TForm1.Button1Click(Sender: TObject);
    var
      CFPRData : TCFPRData;
    begin
      DeleteFile('F:\DD.MKV');  FillChar(CFPRData , SizeOf(CFPRData) , 0);
      CFPRData.PB := ProgressBar1;
      ProgressBar1.Tag := 0;
      ProgressBar1.Position := 0;
      bUserCancel := False;
      CopyFileEx('F:\多媒体\电影收藏\黑衣人3\Men.in.Black.3.2012.720p.BluRay.x264.DTS-HDChina.mkv' ,
                 'F:\DD.MKV' , @CopyFilePR , @CFPRData , NIL , COPY_FILE_FAIL_IF_EXISTS);
    end;这个文件是6G,比直接CopyFile只慢一点点.
      

  9.   

    感谢kiboisme,测试了你的代码,工作正常,效率要比以前有所提高!!!
    可能是因为我的是局域网环境,所以速度也不是太理想!千兆局域网环境!
    手头有个函数,这个速度就比较理想,但遗憾的是不支持大于2G。。能否帮忙改改?
    思路可能是要进行文件分隔与定位。function FileCopy(SourceFile,TargetFile : string;ProgressBar :TProgressBar ) : boolean;
    var
      getStream,setStream: TFileStream;
      num, n: Int;
      buf: PByte;
      BufSize,block: Integer;
    begin
      result := false;
      getStream := TFileStream.Create(SourceFile, fmOpenRead or fmShareCompat);
      setStream := TFileStream.Create(TargetFile, fmCreate);  num := getStream.Size;
      setStream.Size := num;
      getStream.Position := 0;
      setStream.Position := 0;  BufSize := num;
      block := BufSize div 100;
      GetMem(buf, BufSize);  ProgressBar.Max := 100;
      ProgressBar.Position := 0;
      while num <> 0 do
      begin
        Application.ProcessMessages;
        n := block;
        if n > num then n := num;
        getStream.ReadBuffer(buf^, n);
        setStream.WriteBuffer(buf^, n);
        ProgressBar.Position := Trunc((1 - num / BufSize)*100);
        Dec(num, n);
      end;
      ProgressBar.Position := 0;
      FreeMem(buf, BufSize);
      getStream.Free;
      setStream.Free;
      result := true;
    end;
      

  10.   

      BufSize,block: Integer;
    begin
      getStream := TFileStream.Create(SourceFile, fmOpenRead or fmShareCompat);
      num := getStream.Size;  //这里获取文件大小,TStream.Size是一个64位整数,把它赋给以个32位的整数,它的高位自然就被抹杀了,所以超过2G的文件就会出错.  BufSize := num;
      GetMem(buf, BufSize);    //直接申请文件大小的内存,如果是大文件(比如1,2或者3G),那你这程序不是要申请1,2或者3G的内存? 如果要改改动的地方有点多。
        n := block;
       getStream.ReadBuffer(buf^, n);
       从这里看,只使用了block字节的内存,block=文件大小/100,
    却提交了文件大小字节的内存,估计应该是block字节的大小,