Recent

Author Topic: Copy file with progress bar  (Read 1698 times)

Diverod

  • New member
  • *
  • Posts: 7
Copy file with progress bar
« on: November 26, 2023, 08:01:56 pm »
If I set the property of my progesssbar to BarShowText to True in Object Inspector my procedure no longer works (It works fine otherwise). I don’t really need this aspect to work but would like to understand why not if possible.

Lazarus 2.2.0
FPC 3.2.2
Debian package 2.2.0+dfsg1-5ubuntu1 x86_64-linux-gtk2
Ubuntu 22.04 windowing system X11 

I’m trying to move away from windows and found Lazarus, what a jewel, thanks so much to the developers.

Below is a small test app. The Form has a button, label and progressbar.

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ComCtrls;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     btnCopyFile: TButton;
  16.     lblCopyTime: TLabel;
  17.     pgbCurrentFile: TProgressBar;
  18.     procedure btnCopyFileClick(Sender: TObject);
  19.   private
  20.  
  21.   public
  22.  
  23.   end;
  24.  
  25. var
  26.   Form1: TForm1;
  27.  
  28. implementation
  29.  
  30. {$R *.lfm}
  31.  
  32. { TForm1 }
  33. // If you set the ProgressBar to Smooth it will slow the procedure extremely
  34. // If you set the ProgressBar BarShowText to True this will not work.
  35.  
  36. procedure CopyFileWithPgB(Source, Destination: string; PgB: TProgressBar; LbL:
  37.                           TLabel);
  38. // Do FileExists before calling ________________________________________________
  39. var
  40.   FromFile, ToFile: file of byte;
  41.   Buffer: array[0..4096] of char;
  42.   NumRead: integer;
  43.   FileLength: longint;
  44.   StartTime, EndTime: TDateTime;     // Used to show the CopyTime to copy a file
  45. begin
  46.   AssignFile(FromFile, Source);
  47.   reset(FromFile);
  48.   AssignFile(ToFile, Destination);
  49.   rewrite(ToFile);
  50.   FileLength := FileSize(FromFile);
  51.   with PgB do
  52.   begin
  53.     Max:= FileLength;
  54.     StartTime:= now;                 // Used to show the CopyTime to copy a file
  55.  
  56.     while FileLength > 0 do
  57.     begin
  58.       BlockRead(FromFile, Buffer[0], SizeOf(Buffer), NumRead);
  59.       FileLength:= FileLength - NumRead;
  60.       BlockWrite(ToFile, Buffer[0], NumRead);
  61.       Position:= Position + NumRead;
  62.       EndTime:= now;                 // Used to show the CopyTime to copy a file
  63.       LbL.Caption:= FormatDateTime('hh:nn:ss', EndTime - StartTime);
  64.       Application.Processmessages;
  65.     end;
  66.     CloseFile(FromFile);
  67.     CloseFile(ToFile);
  68.   end;
  69. end;
  70.  
  71. procedure TForm1.btnCopyFileClick(Sender: TObject);
  72. var Source, Dest: string;
  73. begin
  74. // Do prechecks to make sure FileExists_________________________________________
  75. Source:='/home/rodg/Desktop/Source/Test.mkv';
  76. Dest:= '/home/rodg/Desktop/Destination1/Test.mkv';
  77.        pgbCurrentFile.Position:= 0;
  78.        CopyFileWithPgB(Source, Dest, pgbCurrentFile, lblCopyTime);
  79.  
  80. end;
  81.  
  82. end.
  83.  

jamie

  • Hero Member
  • *****
  • Posts: 6811
Re: Copy file with progress bar
« Reply #1 on: November 26, 2023, 09:10:59 pm »
Try calling "Update" within your loop which should be the Progressbar.

Also, you can try calling "Repaint";
The only true wisdom is knowing you know nothing

Bart

  • Hero Member
  • *****
  • Posts: 5531
    • Bart en Mariska's Webstek
Re: Copy file with progress bar
« Reply #2 on: November 26, 2023, 09:36:06 pm »
A few remarks:
  • If something goes wrong reading, and numread = 0, you'll have an infinite loop. Common practice is to stop the loop when Numread <> SizeOf(Buffer)
  • There's no error checking
  • IIRC then the Position property has a max on either Windows or *nix, so it won't work as expected for very large files. Better calculate the percentage copied, set MaxValue of the progressbar to 100, round (or floor or ceil) the percentage and use that as the value for Position

Bart

jamie

  • Hero Member
  • *****
  • Posts: 6811
Re: Copy file with progress bar
« Reply #3 on: November 26, 2023, 09:48:05 pm »
I also notice the buffer size is not on an even multiple, maybe it should be [0..4095] instead ?

This may not matter with linux io.
The only true wisdom is knowing you know nothing

Josh

  • Hero Member
  • *****
  • Posts: 1363
Re: Copy file with progress bar
« Reply #4 on: November 26, 2023, 11:05:47 pm »
Proj Attached a copyfile, it uses a modified laz/fpc copydir unit, it was done a couple of years back so cant remember all the mods, mainly to do with progress monitoring and copy file attribs and date etc, think i added in configurable buffer size iirc.

if you untick copy all files, you get presented with extra functions, these were added.

« Last Edit: November 26, 2023, 11:09:19 pm by Josh »
The best way to get accurate information on the forum is to post something wrong and wait for corrections.

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: Copy file with progress bar
« Reply #5 on: November 27, 2023, 12:00:36 am »
Code: Pascal  [Select][+][-]
  1. function CopyFileWithProgress(const ASource, ADestination: UnicodeString; const AProgressBar: TProgressBar): Boolean;
  2. var
  3.   SourceStream, DestStream: TFileStream;
  4.   Buffer: array[0..4095] of Byte;
  5.   BytesRead, TotalBytes, BytesWritten: Integer;
  6. begin
  7.   Result                := False;
  8.   AProgressBar.Min      := 0;
  9.   AProgressBar.Max      := 100;
  10.   AProgressBar.Position := 0;
  11.   { Setup other basics like...
  12.   AProgressBar.Smooth   := True;
  13.   }
  14.   BytesWritten          := 0;
  15.   SourceStream          := TFileStream.Create(String(ASource), fmOpenRead);
  16.   DestStream            := TFileStream.Create(String(ADestination), fmCreate);
  17.   try
  18.     TotalBytes := SourceStream.Size;
  19.     BytesRead := SourceStream.Read(Buffer, SizeOf(Buffer));
  20.     while (BytesRead > 0) do
  21.       begin
  22.         DestStream.Write(Buffer, BytesRead);
  23.         BytesWritten := BytesWritten + BytesRead;
  24.         AProgressBar.Position := (BytesWritten * 100) div TotalBytes;
  25.         BytesRead := SourceStream.Read(Buffer, SizeOf(Buffer));
  26.       end;
  27.     Result := (SourceStream.Size = DestStream.Size);
  28.     if Result then
  29.       AProgressBar.Position := 100;
  30.   finally
  31.     SourceStream.Free;
  32.     DestStream.Free;
  33.   end;
  34. end;
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

Diverod

  • New member
  • *
  • Posts: 7
Re: Copy file with progress bar
« Reply #6 on: November 27, 2023, 07:33:57 pm »
Thank you to everyone for the great comments.

I will go through each comment, test and hopefully learn from it. This will take me a while because my foundation isn't great at this point and it takes me a while to grasp certain things.

Great forum. Thanks!

 

TinyPortal © 2005-2018