大容量ファイルをCopyFile

解決


全自動つま楊枝  2010-05-31 22:11:55  No: 38608

はじめまして、Delphi2年目です。

CopyFile関数を使用して、容量が大きいファイルをコピーする処理があり、
コピー中に画面がフリーズっぽくなる現象を防ぐ為に
Timerを使用して定期的にアニメーションを入れてみたのですが、
コピー中はそのコピーが終了するまでTimerが発生しない為、あまり意味がありません。
コピー中でもTimerイベントを発生させることができる方法はないでしょうか。
Delphi5を使用しています。宜しくお願いします。


monaa  2010-05-31 22:23:06  No: 38609

別スレッドでやらないといずれにせよ固まりますよ。


monaa  2010-05-31 22:29:01  No: 38610

中級者に反応した書き込みでしたが、2年目さんですか。
もう少し詳しく書くと、
普通にプログラムを組むとそれはメインスレッドと呼ばれる主流だけの
プログラムになり、その流れの中で重い操作をすると全体が止まります。
そのため、別の流れを作ってメインスレッドはそれを短時間で時々チェックしに行くようにしなくてはなりません。
重いファイル操作や計算、通信なんかはそのようにするのが一般的です。
Delphiではそれ専用のコンポーネントTThreadというのもがあるので、
それを使ってファイル操作を行います。
概念が、感覚的に理解しづらいと思いますが知らないと先に進めない技術なので頑張ってください。
TTimerはわかりやすく言いえば別スレッドではありません。


全自動つま楊枝  2010-05-31 22:33:02  No: 38611

なるほど、ありがとうございました。
そのやり方で試してみます。


D  2010-06-01 00:20:29  No: 38612

CopyFileEx関数を使う手もあります。

http://cult-drang.com/program/tips/memo/api_copyfileex.html

  private
    { Private 宣言 }
    F_bCancel: Boolean;

  ...

//MoveFileWithProgress, CopyFileExから呼ばれるコールバックルーチン
function CopyProgressRoutine(
  iTotalFileSize:          int64;
  iTotalBytesTransferred:  int64;
  iStreamSize:             int64;
  iStreamBytesTransferred: int64;
  dwStreamNumber:          DWORD;
  dwCallbackReason:        DWORD;
  hSourceFile:             THandle;
  hDestinationFile:        THandle;
  lpData:                  Pointer
): DWORD; stdcall;
begin
  if (iTotalFileSize > 0) then begin
    //0で割るエラーを回避
    Form1.Caption := Format('コピーしています %d%%', [Trunc(iTotalBytesTransferred / iTotalFileSize * 100)]);
  end else begin
    Form1.Caption := 'コピーしています';
  end;
  Application.ProcessMessages;
  Result := PROGRESS_CONTINUE;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  //コピー元ファイルを選択
  if (OpenDialog1.Execute) then begin
    //コピー先ファイルを指定
    SaveDialog1.FileName := OpenDialog1.FileName;
    if (SaveDialog1.Execute) then begin
      F_bCancel := False;
      if (CopyFileEx(
          PChar(OpenDialog1.FileName),
          PChar(SaveDialog1.FileName),
          @CopyProgressRoutine,
          nil,
          @F_bCancel,  //特に必要がなければnilでもOK
          0
      )) then begin
        Caption := 'コピーは成功しました';
      end else begin
        Caption := 'コピーは失敗しました';
      end;
    end;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  F_bCancel := True;
end;


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加