演示两种方法来遍历文件

本文介绍如何在Windows环境中使用Object Pascal通过两种不同的方法遍历文件系统,包括使用Path和Integer等数据类型,深入理解文件操作的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 Unit1.dfm

object Form1: TForm1
  
Left = 248
  Top 
= 107
  BorderStyle 
= bsDialog
  Caption 
= #25991#20214#36941#21382#30340#20363#23376
  ClientHeight 
= 364
  ClientWidth 
= 478
  Color 
= clBtnFace
  Font.Charset 
= ANSI_CHARSET
  Font.Color 
= clWindowText
  Font.Height 
= -12
  Font.Name 
= 'Arial'
  Font.Style = []
  OldCreateOrder 
= False
  OnCloseQuery 
= FormCloseQuery
  PixelsPerInch 
= 96
  TextHeight 
= 15
  
object Label1: TLabel
    
Left = 3
    Top 
= 343
    Width 
= 173
    Height 
= 15
    Caption 
= 'by rockhan  irochan@163.com'
    Font.Charset = ANSI_CHARSET
    Font.Color 
= clWindowText
    Font.Height 
= -12
    Font.Name 
= 'Arial'
    Font.Style = [fsBold]
    ParentFont 
= False
  
end
  
object Bevel1: TBevel
    
Left = 0
    Top 
= 320
    Width 
= 481
    Height 
= 18
    Shape 
= bsBottomLine
  
end
  
object Label2: TLabel
    
Left = 8
    Top 
= 280
    Width 
= 225
    Height 
= 15
    Caption 
= #27809#26377#25214#21040#27494#26519#22806#20256#30340#30446#24405'....'#35831#25442#30424#21518#20877#25214'...'
  end
  
object Memo1: TMemo
    
Left = 0
    Top 
= 0
    Width 
= 473
    Height 
= 273
    ScrollBars 
= ssVertical
    TabOrder 
= 0
  
end
  
object Button1: TButton
    
Left = 296
    Top 
= 304
    Width 
= 75
    Height 
= 25
    Caption 
= #36882#24402#36941#21382
    TabOrder 
= 1
    OnClick 
= Button1Click
  
end
  
object Button2: TButton
    
Left = 384
    Top 
= 304
    Width 
= 75
    Height 
= 25
    Caption 
= #20572#27490
    TabOrder 
= 2
    OnClick 
= Button2Click
  
end
  
object Button3: TButton
    
Left = 208
    Top 
= 304
    Width 
= 75
    Height 
= 25
    Caption 
= #38431#21015#36941#21382
    TabOrder 
= 3
    OnClick 
= Button3Click
  
end
  
object DriveComboBox1: TDriveComboBox
    
Left = 48
    Top 
= 304
    Width 
= 145
    Height 
= 21
    BevelInner 
= bvNone
    BevelOuter 
= bvNone
    TabOrder 
= 4
  
end
end

Unit1.pas

{
演示两种方法来遍历文件

两个函数:
EnumFileInQueue     队列遍历
EnumFileInRecursion 递归遍历

版本:v1.
0

作者:cenjoy 温校宏
邮箱:cenjoyer@
163.com

说明:
看见很多遍历文件的文章都是用递归实现,可是
当子目录非常非常多时,就很容易堆栈溢出.
而使用队列的方法就不会出现这种问题.
不过使用队列这种方法也不是我想出来的,
我从书上看到的,因为发现还有很多人不知道,
所以把它贡献出来.

未解决问题:
1.如何统计遍历的时间和搜索结果
(如何知道用CreateThread创建的线程何时结束)

2.你来说吧~~~~

如果你能解决这些问题,希望你能发一份给我
!!
}
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Contnrs, FileCtrl, ExtCtrls;

type
  TForm1 
= class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    DriveComboBox1: TDriveComboBox;
    Label1: TLabel;
    Bevel1: TBevel;
    Label2: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  
private
    { Private declarations }
    hThreadHandle1:THandle;
    hThreadHandle2:THandle;
  
public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R 
*.dfm}
{用队列的方法遍历文件}
function EnumFileInQueue(path:PChar):Longint;stdcall;
var
    searchRec:TSearchRec;
    found:Integer;
    tmpStr:String;
    curDir:PChar;
    dirs:TQueue;
begin
    Result:
=0;//查找结果(文件数)
    dirs:=TQueue.Create;//创建目录队列
    dirs.Push(path);//将起始搜索路径入队
    curDir:=dirs.Pop;//出队
    {开始遍历,直至队列为空(即没有目录需要遍历)}
    
while (curDir<> nil) do
    begin
        
//加上搜索后缀,得到类似'c:*.*' 、'c:windows*.*'的搜索路径
        tmpStr:=StrPas(curDir)+'*.*';
        
//在当前目录查找第一个文件、子目录
        found:=FindFirst(tmpStr,faAnyFile,searchRec);
        
while found=0 do
        
//找到了一个文件或目录后
        begin
            
//如果找到的是个目录
            if (searchRec.Attr and faDirectory)<>0 then
            begin
                {在搜索非根目录(C:、D:)下的子目录时会出现
'.','..'"虚拟目录"
                 大概是表示上层目录和下层目录吧。。。要过滤掉才可以}
                
if (searchRec.Name <> '.') and (searchRec.Name <> '..') then
                begin
                    {由于查找到的子目录只有个目录名,所以要添上上层目录的路径
                     searchRec.Name 
= 'Windows';
                     tmpStr:
='c:Windows';
                     加个断点就一清二楚了
                     }
                    tmpStr:
=StrPas(curDir)+''+searchRec.Name;
                    {将搜索到的目录入队。让它先晾着。
                    因为TQueue里面的数据只能是指针,所以要把string转换为PChar
                    同时使用StrNew函数重新申请一个空间存入数据,否则会使已经进
                    入队列的指针指向不存在或不正确的数据(tmpStr是局部变量)。}
                    dirs.Push(StrNew(PChar(tmpStr)));
                end;
            end
            
//如果找到的是个文件
            else begin
                {Result记录着搜索到的文件数。可是我是用CreateThread创建线程
                来调用函数的,不知道怎么得到这个返回值。。。我不想用全局变量}
                Result:
=Result+1;
                
//把找到的文件加到Memo控件
                Form1.Memo1.Lines.Add(StrPas(curDir)+''+searchRec.Name);
                form1.Label1.Caption :=(StrPas(curDir)+''+searchRec.Name);
                if searchRec.Name = 'elementclient.exe' then
                begin
                form1.Label2.Caption  :
= strpas(curdir);
               form1.Button2.Click;
                end;

            end;
            
//查找下一个文件或目录
            found:=FindNext(searchRec);
        end;
        {当前目录找到后,如果队列中没有数据,则表示全部找到了;
        否则就是还有子目录未查找,取一个出来继续查找。}
        
if dirs.Count > 0 then
            curDir:
=dirs.Pop
        
else
            curDir:
=nil;
    end;
    
//释放资源
    dirs.Free;
    FindClose(searchRec);
end;

{用递归的方法遍历文件}
function EnumFileInRecursion(path:PChar):Longint;stdcall;
var
    searchRec:TSearchRec;
    found:Integer;
    tmpStr:String;
    pp:integer;
begin
    Result:
=0//查找结果(文件数)
    
//加上搜索后缀,得到类似'c:*.*' 、'c:windows*.*'的搜索路径
    tmpStr:=StrPas(path)+'*.*';
    
//在当前目录查找第一个文件、子目录
    found:=FindFirst(tmpStr,faAnyFile,searchRec);
    
while found=0 do
    
//找到了一个文件或目录后
    begin
        
//如果找到的是个目录
        if (searchRec.Attr and faDirectory)<>0 then
        begin
            {在搜索非根目录(C:、D:)下的子目录时会出现
'.','..'"虚拟目录"
            大概是表示上层目录和下层目录吧。。。要过滤掉才可以}
            
if (searchRec.Name <> '.') and (searchRec.Name <> '..') then
            begin
                {由于查找到的子目录只有个目录名,所以要添上上层目录的路径
                searchRec.Name 
= 'Windows';tmpStr:='c:Windows';
                加个断点就一清二楚了}
                tmpStr:
=StrPas(path)+''+searchRec.Name;
                //自身调用,查找子目录,递归。。。。
                Result:=Result+EnumFileInRecursion(PChar(tmpStr));
            end;
        end
        
//如果找到的是个文件
        {这个也是递归的结束条件,结束条件对于理解递归来说,相当重要}
        
else begin
            {Result记录着搜索到的文件数。可是我是用CreateThread创建线程
            来调用函数的,不知道怎么得到这个返回值。。。我不想用全局变量}
            Result:
=Result+1;
            
//把找到的文件加到Memo控件
            Form1.Memo1.Lines.Add(StrPas(path)+''+searchRec.Name);
            form1.Label1.Caption :=(StrPas(path)+''+searchRec.Name);
            pp := SendMessage(form1.Memo1.Handle,EM_LINEFROMCHAR,-1,0);
            form1.Label2.Caption :
= form1.Memo1.Lines.Strings[pp-1];
            
if searchRec.Name = 'elementclient.exe' then
               begin
                   form1.Label2.Caption :
= strpas(path);
                   form1.Button2.Click;
               end;
            end;
           
// if searchrec.Name <> '' then begin
           
// showmessage('sfksdkfksdf');
           
// end;
         
//查找下一个文件或目录
        found:=FindNext(searchRec);
    end;
    
//释放资源
    FindClose(searchRec);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
    dwThreadID:Cardinal;
    path:String;
begin
    
if hThreadHandle1 = 0 then
    begin
        Memo1.Lines.Clear;
        
//得到驱动盘的路径,这样可能啰嗦了些.
        path:=DriveComboBox1.Drive+':';
        
//创建线程,使用递归方法遍历文件
        hThreadHandle1:=CreateThread(nil,0,@EnumFileInRecursion,StrNew(PChar(path)),0,dwThreadID);
        {@EnumFileInRecursion是函数的地址
        PChar(
'c:')是函数的参数,以指针传递
        不能直接使用@EnumFileInRecursion(
'c:')}
    end 
else
    begin
        TerminateThread(hThreadHandle1,
0);
        CloseHandle(hThreadHandle1);
        hThreadHandle1 :
= 0;
    end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
//结束线程
    if hThreadHandle1 <> 0 then
    begin
        TerminateThread(hThreadHandle1,
0);
        CloseHandle(hThreadHandle1);
        hThreadHandle1 :
= 0;
    end;

    
if hThreadHandle2 <> 0 then
    begin
        TerminateThread(hThreadHandle2,
0);
        CloseHandle(hThreadHandle2);
        hThreadHandle2 :
= 0;
    end;
end;

procedure TForm1.Button3Click(Sender: TObject);
var
    dwThreadID:Cardinal;
    path:String;
begin
    
if hThreadHandle2 = 0 then
    begin
        Memo1.Lines.Clear;
        
//得到驱动盘的路径,这样可能啰嗦了些.
        path:=DriveComboBox1.Drive+':';
        
//创建线程,使用队列方法遍历文件
        hThreadHandle2:=CreateThread(nil,0,@EnumFileInQueue,StrNew(PChar(path)),0,dwThreadID);
        {@EnumFileInRecursion是函数的地址
        PChar(
'c:')是函数的参数,以指针传递
        不能直接使用@EnumFileInRecursion(
'c:')}
    end
    
else begin
        TerminateThread(hThreadHandle2,
0);
        CloseHandle(hThreadHandle2);
        hThreadHandle2 :
= 0;
    end;
end;

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  CanClose:
=false;
//结束线程
    if hThreadHandle1 <> 0 then
    begin
        TerminateThread(hThreadHandle1,
0);
        CloseHandle(hThreadHandle1);
        hThreadHandle1 :
= 0;
    end;

    
if hThreadHandle2 <> 0 then
    begin
        TerminateThread(hThreadHandle2,
0);
        CloseHandle(hThreadHandle2);
        hThreadHandle2 :
= 0;
    end;
  CanClose:
=true;
end;

end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pzhan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值