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
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.
演示两种方法来遍历文件
两个函数:
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.