-1

I'm trying to make progressbar while deleting files here is my code:

procedure TForm1.Timer1Timer(Sender: TObject);
var
  i:Integer; 
begin 
    i:=i+1; 
    ProgressBar.Max:=DeleteList.Count - i ; //Files = 8192       
    DeleteFile(GetIniString('List', 'File' + IntToStr(i),'','FileLists.ini'));        
    ProgressBar.Position:=ProgressBar.Position+1;
end;
R. Hoek
  • 916
  • 8
  • 27
AkA
  • 13
  • 5
  • What problem are you having? What's your actual question? – Jerry Dodge Oct 27 '19 at 15:42
  • my question is., Is it possible to delete files with Tprogressbar like FOF_SIMPLEPROGRESS – AkA Oct 27 '19 at 15:47
  • What have you tried so far? Where did it go wrong? – Jerry Dodge Oct 27 '19 at 15:54
  • 7
    On Windows use IFileOperation – David Heffernan Oct 27 '19 at 16:02
  • 1
    Your code seems wrong. The variable `i` does not retain its value between calls to `Timer1Timer` because it is allocated on the stack; if it appears to, it is only because of lucky intervening stack usage. Also, reading the name of the file from an Ini file is an awfully slow way to do it: Instead, save the names of the files you want to delete in a stringlist and get the names from that. – MartynA Oct 27 '19 at 17:36

2 Answers2

3

Using threads or IFileOperation both involve fairly steep learning curves. Here are a couple of possibilities:

TDirectory method

At Jerry Dodge's prompting I decided to add an example of using TDirectory to get a list of files and process it in some way, e.g. delete files in the list.

It displays a periodic progress message - see the if i mod 100 = 0 then statement in the ProcessFiles method. Unfortunately I couldn't find a way to show a periodic message during the list-building stage because AFAIC TDirectory doesn't expose the necessary hook to do so.

procedure TForm2.ProcessFileList(FileList : TStringList);
var
  i : Integer;
  S : String;
begin
  for i := 0 to FileList.Count - 1 do begin
    // do something with FileList[i], e.g. delete it
    S := FileList[i];
    DeleteFile(S);

    //  Display progress
    if i mod 100 = 0 then // do something to show progress
      Caption := Format('Files processed: %d ', [i]);
      // OR, you could use i and FileList.Count to set a trackbar % complete
  end;
  Caption := Format('Processed: %d files', [FileList.Count]);
end;

procedure TForm2.GetFileList(const Path : String; FileList : TStringList);
var
  Files : Types.TStringDynArray;
  i : Integer;
begin
  Files := TDirectory.GetFiles('C:\Temp');
  FileList.BeginUpdate;
  try
    for i:= 0 to Length(Files) - 1 do
      FileList.Add(Files[i]);
  finally
    FileList.EndUpdate;
  end;
end;

procedure TForm2.Button1Click(Sender: TObject);
var
  FileList : TStringList;
begin
  FileList := TStringList.Create;
  try
    GetFileList('C:\Temp', FileList);
    ProcessFileList(FileList);
    Memo1.Lines.Text := FileList.Text;
  finally
    FileList.Free;
  end;
end;

It should be evident that this way of doing it is a lot simpler than using the traditional, Windows-specific method below, at the expense of loss of some flexibility, and has the advantage of being cross-platform.

IFileOperation method (Windows-specific)

The Windows API has functionality to retrieve and process a list of files e.g. in a directory and there used to be a trivially-simple-to-use wrapper around this, including a progress animation, in the (antique) v.3 of SysTools library from TurboPower S/Ware, but I'm not sure this wrapper ever made it into the later public domain version. On the face if it, it could also be done using the IFileOperation interface but google has yet to conjure a simple example. Note that an SO answer about this contains the comment "this is a very complex API and you do need to read the documentation carefully".

I attempted to do this myself but soon got out of my depth. Remy Lebeau's answer here to the q I posted when I got stuck shows how to do it, but the TDirectory method above seems vastly easier at my skill level.

Traditional (D7) method (Windows-specific)

In my experience, if you are only looking to process a few hundred thousand files, you should be able to do it, displaying progress as you go, by adding the files to a TStringList and then processing that, with code along the following lines:

procedure GetFileList(const Path : String; Recurse : Boolean; FileList : TStringList);
// Beware that the following code is Windows-specific
var
  FileCount : Integer;

  procedure GetFilesInner(sPath : String);
  var
    Path,
    AFileName,
    Ext: String;
    Rec: TSearchRec;
    Done: Boolean;
  begin

    Path := IncludeTrailingBackslash(sPath);
    if FindFirst(Path + '*.*', faAnyFile, Rec) = 0 then begin
        Done := False;
        while not Done do begin
         if (Rec.Name <> '.') and (Rec.Name <> '..') then begin
            AFileName := Path + Rec.Name;
            Ext := LowerCase(ExtractFileExt(AFileName));
           if not ((Rec.Attr and faDirectory) = faDirectory) then begin
             inc(FileCount);
             if FileCount mod 100 = 0 then
               //show progress in GUI
               ;
             FileList.Add(AFileName)
           end
           else begin
             if Recurse then
               GetFilesInner(AFileName);
           end;
         end;
         Done := FindNext(Rec) <> 0;
        end;
      FindClose(Rec);
    end;
  end;

begin
  FileCount := 0;
  FileList.BeginUpdate;
  FileList.Sorted := True;
  FileList.Duplicates := dupIgnore;  // don't add duplicate filenames to the list

  GetFilesInner(Path);
  FileList.EndUpdate;
end;


procedure TForm1.Button2Click(Sender: TObject);
var
  FileList : TStringList;
  FileName : String;
  i : Integer;
begin
  FileList := TStringList.Create;
  try
    GetFileList('d:\aaad7', True, FileList);
    for i := 0 to FileList.Count - 1 do begin
      FileName := FileList[i];
      //  do something with FileName, e.g. delete the file
      if i mod 100 = 0 then
        // display progess e.g. by
        Caption := IntToStr(i);
    end;
    Memo1.Lines := FileList;
  finally
    FileList.Free;
  end;

end;

The if [...] mod [...] = 0 then statements are where you can show the two phases' progress howver you want.

Btw, this code was olny intended to get you started. I'm obliged to Jerry Dodge for reminding me that in recent versions of Delphi, there is similar functionality built-in, by way of the TDirectory.GetFiles method so if you are interested in cross-platform and/or accommodate Unicode, you would do better to study the ins and outs of TDirectory and non-Windows-specific routines like TrailingPathDelim.

MartynA
  • 30,454
  • 4
  • 32
  • 73
  • In later versions of Delphi, `TDirectory.GetFiles` is much easier and cleaner than the whole `FindFirst`, `FindNext`, `FindClose` method. – Jerry Dodge Oct 27 '19 at 20:22
  • 2
    @JerryDodge: Indeed, but the OP didn't say which Delphi version (I always pitch answers at D7 unless the q obviously refers to a later v), and in any case it does no harm to know how to do these things yourself if poss. – MartynA Oct 27 '19 at 20:26
  • Indeed, and understood. But perhaps you could add that alternative to your answer for those who are :-) – Jerry Dodge Oct 27 '19 at 20:36
  • 1
    @MartynA One small note for multi target platforms: use IncludeTrailingPathdelim instead of IncludeTrailingBackslash – R. Hoek Oct 27 '19 at 21:25
  • @MartynA I've been focusing on at least the unicode enforced versions of Delphi when assuming version compatibility. That seems to be a major divider into two entirely different realms of programming. – Jerry Dodge Oct 27 '19 at 21:39
  • There are also two ways you can approach this. Either you monitor the progress of data size being deducted during deletion, or you monitor the number of files being deleted. It depends on the quantity of deletions. – Jerry Dodge Oct 27 '19 at 22:26
  • Ugh, IFileOperation is so much simpler than this, and so much better for the user. – David Heffernan Oct 28 '19 at 08:16
  • @DavidHeffernan: (2nd attempt) Sure, if you have one of those component wrappers around shell objects, etc handy, otherwise you need to know how to go about it, surely? – MartynA Oct 28 '19 at 08:42
  • I would never use one of those component wrappers. I personally don't think it's that hard. And there's a huge benefit for the user. – David Heffernan Oct 28 '19 at 09:33
  • @JerryDodge: See today's update, I decided to take up your suggestion. – MartynA Oct 28 '19 at 12:15
0

When you really want to show some progress in a UI when deleting files, you should use threads:

  • create a thread, which deletes the files
  • then poll the progress of the deletion thread from the UI

Be careful when using threads, not to access UI parts (like the progressbar) from within the deletion thread. Such things should at least be synchronized.

Jerry Dodge
  • 26,858
  • 31
  • 155
  • 327
R. Hoek
  • 916
  • 8
  • 27
  • how to poll it from Ul and second window will not hide – AkA Oct 27 '19 at 15:52
  • @AkA you can then just use the timer to ‘read’ the progress from the thread.... – R. Hoek Oct 27 '19 at 15:54
  • Thread:=TThread.CreateAnonymousThread( procedure begin DeleteFolder('I:\J.A\Script\Output\Files'); end); Thread.Start; – AkA Oct 27 '19 at 16:11
  • This approach is perhaps unnecessarily complicated for what the OP wants - see @DavidHeffernan's comment. – MartynA Oct 27 '19 at 17:03
  • @MartynA maybe true, but the first thing devs run into after creating these kind of things is the fact the ui blocks and isnt updated while the progressbar is updated... So you fall back into the app.progressmessages and so on... so i would rather start the right way even though it’s complex. – R. Hoek Oct 27 '19 at 18:27
  • Fair comment about apm. But the OP should get his code right before dipping into threads ... – MartynA Oct 27 '19 at 18:43
  • [Some related reading](https://github.com/djjd47130/DelphiThreadDemo/blob/master/README.md#can-i-use-vcl-from-a-thread) about why threads aren't so straight-forward, especially for beginners. – Jerry Dodge Oct 27 '19 at 19:17
  • @JerryDodge nice background info on thread use in combination with UI – R. Hoek Oct 27 '19 at 19:19
  • @R.Hoek Thanks, I slapped that project together a while back as a result of seeing threads mis-used so often here on SO. Someone suggested the idea of a brief article explaining thread safety, so I went ahead and whipped that together. Haven't worked on it in a while though. I anticipated the open-source community to help contribute and make it a decent guide to multithreading in Delphi. – Jerry Dodge Oct 27 '19 at 19:27
  • @MartynA thanks mate your answer is absolutely right finally worked – AkA Oct 27 '19 at 20:48
  • Glad it's got you going. Please feel free to accept my answer by clicking the 'tick' icon on its lhs if it suits you best.. – MartynA Oct 27 '19 at 20:50