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.