Delphi 使用progressbar删除文件

Delphi 使用progressbar删除文件,delphi,Delphi,我试图在删除文件时使用progressbar,以下是我的代码: 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),'','FileLi

我试图在删除文件时使用progressbar,以下是我的代码:

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;

如果确实希望在删除文件时在UI中显示某些进度,则应使用线程:

  • 创建一个线程,删除文件
  • 然后从UI轮询删除线程的进度

使用线程时要小心,不要从删除线程中访问UI部件(如progressbar)。这样的事情至少应该同步。

使用线程或IFileOperation都需要相当陡峭的学习曲线。以下是几种可能性:

t目录方法

在Jerry Dodge的提示下,我决定添加一个使用TDirectory的示例 获取文件列表并以某种方式进行处理,例如删除列表中的文件

它会显示一条周期性进度消息-请参见
如果i mod 100=0则
语句
在
ProcessFiles
方法中。不幸的是,我找不到一个展示的方式 由于AFAIC TDirectory,在列表构建阶段出现一条周期性消息 不暴露必要的钩子来执行此操作

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;
显然,这种方法比使用 传统的特定于Windows的方法,以牺牲一些灵活性为代价, 具有跨平台的优势

i操作方法(特定于Windows)

Windows API具有检索和处理文件列表的功能,例如在一个目录中,在TurboPower S/Ware的SysTools库(仿古版)v.3中,曾经有一个简单易用的包装,包括一个进度动画,但我不确定这个包装是否能进入更高的公共域版本。从表面上看,如果可以的话,也可以使用IFileOperation界面来实现,但谷歌还没有想出一个简单的例子。请注意,关于这一点的答案包含注释“”

我试图自己做这件事,但很快就不知所措了。雷米·勒博(Remy Lebeau)对我被卡住时发布的问题的回答说明了如何做到这一点,但在我的技能水平上,上面的t目录方法似乎要简单得多

传统(D7)方法(特定于Windows)

根据我的经验,如果您只希望处理几十万个文件,您应该能够做到这一点,通过将文件添加到TStringList中,然后使用以下代码进行处理,在运行过程中显示进度:

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;
procedure-GetFileList(const-Path:String;Recurse:Boolean;FileList:TStringList);
//请注意,以下代码是特定于Windows的
变量
FileCount:整数;
过程GetFilesInner(sPath:String);
变量
路径
阿菲尔名字,
外部:字符串;
Rec:TSearchRec;
完成:布尔;
开始
路径:=包含轨道反斜杠(sPath);
如果FindFirst(路径+'*.*',faAnyFile,Rec)=0,则开始
完成:=错误;
未完即开始
如果是(Rec.Name'')和(Rec.Name'..'),则开始
AFileName:=路径+记录名;
Ext:=小写(ExtractFileExt(AFileName));
如果不是((Rec.Attr和faDirectory)=faDirectory),则开始
公司(文件计数);
如果FileCount mod 100=0,则
//在GUI中显示进度
;
FileList.Add(文件名)
结束
否则开始
如果再次发生,那么
GetFilesInner(AFileName);
结束;
结束;
完成:=FindNext(Rec)0;
结束;
FindClose(Rec);
结束;
结束;
开始
文件计数:=0;
FileList.BeginUpdate;
FileList.Sorted:=True;
FileList.Duplicates:=dupIgnore;//不要向列表中添加重复的文件名
GetFilesInner(路径);
FileList.EndUpdate;
结束;
程序TForm1.按钮2单击(发送方:TObject);
变量
文件列表:TStringList;
文件名:字符串;
i:整数;
开始
FileList:=TStringList.Create;
尝试
GetFileList('d:\aaad7',True,FileList);
对于文件列表中的i:=0。计数-1是否开始
FileName:=文件列表[i];
//对文件名执行某些操作,例如删除文件
如果我mod 100=0,那么
//显示进度,例如通过
标题:=IntToStr(i);
结束;
备注1.行:=文件列表;
最后
文件列表。免费;
结束;
结束;
如果[…]mod[…]=0,则可以在
语句中显示两个阶段的进度,无论您希望如何


顺便说一句,这段代码是奥尔尼打算让你开始的。我不得不感谢Jerry Dodge提醒我,在Delphi的最新版本中,通过TDirectory.GetFiles方法内置了类似的功能,因此如果您对跨平台和/或采用Unicode感兴趣,您最好研究TDirectory和非Windows特定例程(如TrailingPathDelim)的详细信息。

您遇到了什么问题?你真正的问题是什么?我的问题是,有没有可能用像FOF_simpleprogressbar这样的Tprogressbar删除文件?到目前为止,你做了哪些尝试?哪里出错了?在Windows上使用IFileOperation您的代码似乎出错了。变量
i
在调用
Timer1Timer
之间不保留其值,因为它是在堆栈上分配的;如果看起来是这样,那只是因为幸运的介入堆栈使用。另外,从Ini文件读取文件名是一种非常缓慢的方法:相反,将要删除的文件的名称保存在stringlist中,并从中获取名称。如何从Ul和第二个窗口对其进行轮询将不起作用hide@AkA然后,您可以使用计时器从线程中“读取”进度……线程:=TThread.CreateAnonymousThread(过程begin DeleteFolder('I:\J.A\Script\Output\Files');end);线程。开始;对于OP想要的东西来说,这种方法可能是不必要的复杂-参见@DavidHeffernan的评论。@MartynA可能是真的,但开发者在创建此类东西后遇到的第一件事是,当程序运行时,ui会被阻塞并且不会被更新