Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 244
  • Last Modified:

Background copy in threads

Hi guys,

the goal is to copy files in the background.
I have an app on which you can drop files. I don't want the
app, to freeze, when it copies files. I want to be capable to
drop other files on it, even when there is still a file or files
being copied.
So I thought of using a thead, but I'm not very avare on how it is working.
Anyway I'm to lazy to search about how it is working.

Here is my copy function:

procedure copyFichier(const source, dest: string);
var
     S, D: TFileStream;
begin
     S := TFileStream.Create(source, fmOpenRead or fmShareDenyWrite);
     try
          D := TFileStream.Create(dest, fmCreate or fmOpenWrite or fmShareExclusive);
          try
               D.CopyFrom(S, S.Size);
          finally
               D.Free;
          end;
     finally
          S.Free;
     end;
end;

It is not very important, to have it anyway.
it is called in the middle of another of my procedures:
...
CopyFichier(sourceFile, destDir);
...

I want that copy to happen in background, how can I do that ?

I need a counter of how many copy are still active.
I want working source code please.
Thanks for your help.
0
jeurk
Asked:
jeurk
  • 10
  • 6
  • 3
  • +1
1 Solution
 
d003303Commented:
Yo,
I think you should better work with a copy list. Take the first file on the list and start the copy thread. When copying is finished, delete the entry and repeat until the list is empty. During copying, the list can be extended with dropping entries onto it. Copying several files at once may be good when ftping in the internet, but not on local networks or on the same machine.
Also, the copy thread should give feedback about the copying status and provide an abort handler. For that you have to copy in small buffers, not one stream into another.
I'll take a look at it.

Slash/d003303
0
 
d003303Commented:
Yo,
here's some code about what I mentioned above.

/////////////////////
// to be ThrdCopy.dpr
program ThrdCopy;

uses
  Forms,
  copywnd in 'copywnd.pas' {Form1};

{$R *.RES}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

/////////////////////
// to be copywnd.pas
unit copywnd;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ComCtrls, StdCtrls, cpythrd, ExtCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Button1: TButton;
    Button2: TButton;
    ProgressBar1: TProgressBar;
    Panel1: TPanel;
    Label1: TLabel;
    Animate1: TAnimate;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
    FCopyThread : TCopyThread;
  public
    { Public declarations }
    procedure ThreadFeedback(Sender : TObject);
    procedure ThreadTerminate(Sender : TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
begin
  FCopyThread := TCopyThread.Create(Edit1.Text, Edit2.Text);
  FCopyThread.OnFeedback := ThreadFeedback;
  FCopyThread.OnTerminate := ThreadTerminate;
  FCopyThread.FreeOnTerminate := false;
  Button2.Enabled := true;
  Button1.Enabled := false;
  Animate1.Visible := true;
  Animate1.Active := true;
  FCopyThread.StartCopy;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  FCopyThread.Terminate;
end;

procedure TForm1.ThreadFeedback(Sender : TObject);
begin
  if Sender is TCopyThread then
   with Sender as TCopyThread do
    begin
      Panel1.Caption := Format('  %d of %d bytes copied', [BytesCopied, SourceSize]);
      Panel1.Refresh;
      ProgressBar1.Position := PercentCopied;
      ProgressBar1.Refresh;
      Application.ProcessMessages;
    end;
end;

procedure TForm1.ThreadTerminate(Sender : TObject);
begin
  if Sender is TCopyThread then
   begin
     Button2.Enabled := false;
     Button1.Enabled := true;
     Animate1.Visible := false;
     Animate1.Active := false;
     ProgressBar1.Position := 0;
     if (Sender as TCopyThread).ReturnValue = 0
      then Panel1.Caption := '  copying succeeded.'
      else Panel1.Caption := '  copying not succeeded.';
     Sender.Free;
   end;
end;

end.

/////////////////////
// to be copywnd.dfm
object Form1: TForm1
  Left = 200
  Top = 108
  Width = 340
  Height = 211
  BorderStyle = bsSizeToolWin
  Caption = 'Thread-Copy'
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 160
    Top = 12
    Width = 9
    Height = 13
    Caption = '->'
  end
  object Edit1: TEdit
    Left = 4
    Top = 8
    Width = 153
    Height = 21
    TabOrder = 0
  end
  object Edit2: TEdit
    Left = 172
    Top = 8
    Width = 153
    Height = 21
    TabOrder = 1
  end
  object Button1: TButton
    Left = 84
    Top = 64
    Width = 75
    Height = 25
    Caption = 'Copy'
    TabOrder = 2
    OnClick = Button1Click
  end
  object Button2: TButton
    Left = 172
    Top = 64
    Width = 75
    Height = 25
    Caption = 'Cancel'
    Enabled = False
    TabOrder = 3
    OnClick = Button2Click
  end
  object ProgressBar1: TProgressBar
    Left = 4
    Top = 40
    Width = 321
    Height = 16
    Min = 0
    Max = 100
    TabOrder = 4
  end
  object Panel1: TPanel
    Left = 0
    Top = 164
    Width = 332
    Height = 20
    Align = alBottom
    Alignment = taLeftJustify
    BevelOuter = bvLowered
    TabOrder = 5
  end
  object Animate1: TAnimate
    Left = 24
    Top = 96
    Width = 272
    Height = 60
    Active = False
    CommonAVI = aviCopyFiles
    StopFrame = 34
    Visible = False
  end
end

/////////////////////
// to be cpythrd.pas

unit cpythrd;

interface

uses
  Windows, Classes;

const
  MaxBufSize = 4096;

type

  TCopyThread = class(TThread)
  private
    FCopyBuffer    : array[0..MaxBufSize - 1] of Byte;
    FSource,
    FDestination   : string;
    FHSource,
    FHDestination  : THandle;
    FSourceSize,
    FBytesCopied   : LongInt;
    FPercentCopied : Integer;
    FOnFeedback    : TNotifyEvent;
    procedure GiveFeedback;
  protected
    procedure Execute; override;
  public
    procedure StartCopy;
    constructor Create(Source, Destination : string);
    destructor Destroy; override;
    property Source: string read FSource;
    property Destination: string read FDestination;
    property PercentCopied: Integer read FPercentCopied;
    property SourceSize: LongInt read FSourceSize;
    property BytesCopied: LongInt read FBytesCopied;
    property ReturnValue;
    property OnFeedback: TNotifyEvent read FOnFeedback write FOnFeedback;
  end;

implementation

procedure TCopyThread.GiveFeedback;
begin
  if Assigned(FOnFeedback)
   then FOnFeedback(Self);
end;

procedure TCopyThread.Execute;
var BytesRead,
    BytesWritten : Integer;
begin
  repeat
    if not ReadFile(FHSource, FCopyBuffer, MaxBufSize, BytesRead, nil)
     then Exit;
    if not WriteFile(FHDestination, FCopyBuffer, BytesRead, BytesWritten, nil)
     then Exit;
    if BytesRead <> BytesWritten
     then Exit;
    FBytesCopied := FBytesCopied + BytesWritten;
    FPercentCopied := Trunc(100 / FSourceSize * FBytesCopied);
    Synchronize(GiveFeedback);
    if Terminated then Exit;
  until FBytesCopied = FSourceSize;
  ReturnValue := 0;
end;

procedure TCopyThread.StartCopy;
begin
  Execute;
end;

constructor TCopyThread.Create(Source, Destination : string);
var OFStruct : TOFStruct;
begin
  inherited Create(false);
  ReturnValue := 1;
  FSource := Source;
  FDestination := Destination;
  // check source file
  OFStruct.cBytes := SizeOf(TOFStruct);
  FHSource := OpenFile(PChar(FSource), OFStruct, OF_READ);
  if FHSource = HFILE_ERROR
   then Exit;
  FSourceSize := GetFileSize(FHSource,nil);
  if FSourceSize = $FFFFFFFF
   then Exit;
  // check destination
  FHDestination := OpenFile(PChar(FDestination), OFStruct, OF_CREATE);
  if FHDestination = HFILE_ERROR
   then Exit;
  FBytesCopied := 0;
  FPercentCopied := 0;
end;

destructor TCopyThread.Destroy;
begin
  if FHSource <> HFILE_ERROR
   then CloseHandle(FHSource);
  if FHDestination <> HFILE_ERROR
   then CloseHandle(FHDestination);
  inherited Destroy;
end;

end.

/////////////////////////////////////////////////////////////////

The stuff uses VERY basic error-handling, that's still to do.

Have fun,
Slash/d003303
0
 
jeurkAuthor Commented:
Hi,
Thanks for the answer, I'll try out the things.
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
jeurkAuthor Commented:
Hi, I reject your answer, cause it is not working properly,
the copy does never stop. If you want to change the thing
and it works you will earn a B, but if you want you can say
that you won't change the answer and only earn a D.
What do you think d003303 ?
0
 
d003303Commented:
Yo,
on all my machines it works fine (NT 4.0), have you tracked the value of the FBytesCopied variable in the debugger ? Or is your file larger than 4294967295 bytes (32 bit boundary) ?

Slash/d003303
0
 
jeurkAuthor Commented:
Hi,
I tryed it under W95, even on small files.
Maybe you could send me the whole project that you have on
your computer ? that would avoid some typos ?

Mailto://knipjo@citeweb.net

Thanks.
0
 
jeurkAuthor Commented:
Have you sent the projects or not ?
Will you send it or not ?
Do you want the points ?
Let me hear from you.

Jeurk
0
 
d003303Commented:
huh, totaly forgot about this one ! I've send you the project including my EXE. Let's work it out until it works on your machine.

Slash/d003303
0
 
BlackManCommented:
How about this: "Multithread copy is what should have been done in any decent file manager under Windows 95/NT. It allows to launch as many copy operations as wanted without any need to wait till the operation's completed - by Daniel Doubrovkine "

It comes with complete source!!
It's on Delphi Super Page (http://sunsite.icm.edu.pl/delphi), search for MUCOPY
0
 
jeurkAuthor Commented:
Where is your cool answer blackman ?
Huh?

0
 
BlackManCommented:
Oops, I'm sorry I tried to help you...
0
 
jeurkAuthor Commented:
I apologize :
In your answer there was nothing but an empty box, so I thought you
made a mistake. I'm really sorry. There might have been a problem.
I'll take a look at what you say.
Thanks.

[d003303] I tryed what you sent : it is working an small files, but this time
on large files it copys everything, stops when the bytes number are equal
in src and dest but don't gives the hand back.


0
 
jeurkAuthor Commented:
It seems cool,
I'll let ya know what I think of it.
Jeurk
0
 
d003303Commented:
I'll take a look at it.
0
 
Edo082297Commented:
Hi
  I don't know if this is your problem, but you should try moving the inherited create to the last statement in your constructor. That way, the initial initialization will be done, and the process can get underway (i.e. Execute) immediately.
  I could be way off on this one.

HTH

Edo
0
 
jeurkAuthor Commented:
Thanks for the help EDO.

Anyway, blackman : I think you're gonna earn the points cause the link you
submitted shows a perfectly working solution.
If everyone agrees ?
d003 ?

Regards
0
 
d003303Commented:
It has to work for *you*, so if you think so, no prob.
0
 
jeurkAuthor Commented:
Cool that you take it like that d003303. Anyway we will meet again
around others questions. I am aware that you gave out some work here.
Nochmal danke.
Jeurk.

Blackman : answer that question please.


0
 
BlackManCommented:
How about this: "Multithread copy is what should have been done in any decent file manager under Windows 95/NT. It allows to launch as many copy operations as wanted without any need to wait till the operation's completed - by Daniel Doubrovkine " 

It comes with complete source!!
It's on Delphi Super Page (http://sunsite.icm.edu.pl/delphi), search for MUCOPY
0
 
jeurkAuthor Commented:
I apologize again ;)
Thanks for the links it does the job well.
Jeurk
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

  • 10
  • 6
  • 3
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now