多线程操作一例:查找 pas dfm 里的中文
2010-11-02 17:06:58 来源:WEB开发网核心提示:查找一个pas文件里的汉字,需要打开此文件,多线程操作一例:查找 pas dfm 里的中文,逐行读出,判断,在添加一个TCNFile文件时需要进行同步,否则会造成同时访问FFiles出错,查找 dfm 与上相似,但dfm里的汉字是使用数值来表示的
查找一个pas文件里的汉字,需要打开此文件,逐行读出,判断。
查找 dfm 与上相似,但dfm里的汉字是使用数值来表示的,需要用widechar转换过来。此外汉字开始标记为 "#" (不准确)。
程序实现
1、TFileLine 一行文字
2、TCNFile 一个含有汉字的文件
3、TFolder 一个文件夹
4、TFileThread 文件处理线程
注释
使用标准文件查找的方式进行文件查找,遇到pas或dfm文件时,开启线程对其操作(此处为异步线程)。关于线程同步,在添加一个TCNFile文件时需要进行同步,否则会造成同时访问FFiles出错。
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ComCtrls,Contnrs,SyncObjs, ImgList, RzStatus, RzPanel; type TFileLine = class private FLine:Integer; FContext:String; public { 功能:行号} property Line:Integer read FLine write FLine; { 功能:内容} property Context:String read FContext write FContext; end; TCNFile = class private FHashCN:Boolean; FContexts:TObjectList; FName:string; function GetCount:Integer; function GetContexts(const Index:integer):TFileLine; public destructor destroy;override; { 功能:含有中文} property HashCN:Boolean read FHashCN write FHashCN; { 功能:文件名} property Name:string read FName write FName; { 功能:添加} function Add:TFileLine; { 功能:数量} property Count:Integer read GetCount; { 功能:内容} property Contexts[const Index:integer]:TFileLine read GetContexts; end; TFolder = class private FFiles:TObjectList; FFolders:TObjectList; FCS:TCriticalSection; FName:string; function GetCount:Integer; function GetFiles(const Index:integer):TCNFile; function GetFolderCount:Integer; function GetFolders(const Index:integer):TFolder; public constructor Create; destructor Destroy;override; { 功能:文件夹名} property Name:string read FName write FName; { 功能:添加} function Add:TCNFile; function AddFoler:TFolder; { 功能:数量} property Count:Integer read GetCount; { 功能:内容} property Files[const Index:integer]:TCNFile read GetFiles; { 功能:数量} property FolderCount:Integer read GetFolderCount; { 功能:内容} property Folders[const Index:integer]:TFolder read GetFolders; end; // PFileRec = ^TFileRec; // TFileRec = record // Data:TCNFile; // end; TFileMethod = procedure (const Folder:TFolder;const FileName:string) of object; TFileThread = class(TThread) private FFolder:TFolder; FFileName:String; FMethod:TFileMethod; protected procedure Execute;override; public { 功能:文件夹} property Folder:TFolder read FFolder write FFolder; { 功能:文件} property FileName:String read FFileName write FFileName; { 功能:方法} property Method:TFileMethod read FMethod write FMethod; end; TForm1 = class(TForm) Panel1: TPanel; Splitter1: TSplitter; Memo1: TMemo; Label1: TLabel; edt_Path: TEdit; Button1: TButton; TreeView1: TTreeView; ImageList1: TImageList; GroupBox1: TGroupBox; cb_include: TCheckBox; cb_Svn: TCheckBox; cb_Dcu: TCheckBox; RzStatusBar1: TRzStatusBar; stProgress: TRzProgressStatus; cb_CN: TCheckBox; stText: TRzStatusPane; procedure Button1Click(Sender: TObject); procedure TreeView1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure TreeView1DblClick(Sender: TObject); procedure edt_PathDblClick(Sender: TObject); procedure cb_CNClick(Sender: TObject); procedure stTextDblClick(Sender: TObject); private ThreadCount:Integer; FileCount:Integer; FLast:TTreeNode; FCS:TCriticalSection; Root:TFolder; procedure SearchProc(const Parent:TFolder;const Path:string); procedure DoFile(const Folder:TFolder;const FileName:string); procedure ThreadEnd(sender:TObject); procedure MakeTree; procedure WaitFor; public { Public declarations } end; var Form1: TForm1; implementation uses BrowseForFolderU,ShellAPI; {$R *.dfm} { TForm1 } procedure TForm1.SearchProc(const Parent:TFolder;const Path:string); function GetFolderName:string; var i:Integer; begin i:=Length(ExtractFileDir(Path)); Result:=Path; Delete(Result,1,i + 1); end; var SearchRec: TSearchRec; iResult:Integer; extName:string; _Path:string; _Folder:TFolder; _FileThread:TFileThread; begin if not DirectoryExists(Path) then Exit; _Path:=Path; if Path[Length(Path)] <> '\' then _Path:=Path + '\'; // if Assigned(Parent) then _Folder:=Parent.AddFoler; _Folder.Name:=GetFolderName; iResult:=FindFirst(_Path + '*.*', faAnyFile, SearchRec); while iResult = 0 do begin if (SearchRec.Attr and faDirectory = faDirectory) then begin if (SearchRec.Name <> '.') and (SearchRec.Name <> '..') then begin if cb_Svn.Checked and SameText(SearchRec.Name,'.svn') then begin iResult:=FindNext(SearchRec); Continue; end; if cb_Dcu.Checked and SameText(SearchRec.Name,'.dcu') then begin iResult:=FindNext(SearchRec); Continue; end; if cb_include.Checked then SearchProc(_Folder,_Path + SearchRec.Name); end; end else begin extName:=ExtractFileExt(SearchRec.Name); if SameText(extName,'.pas') or SameText(extName,'.dfm') then begin Inc(FileCount); stProgress.PartsComplete:= FileCount ; stProgress.Update; _FileThread:=TFileThread.Create(True); _FileThread.Folder:=_Folder; _FileThread.FileName:=_Path + SearchRec.Name; _FileThread.Method:=DoFile; _FileThread.OnTerminate:=ThreadEnd; Inc(ThreadCount); _FileThread.Resume; _FileThread.WaitFor; end; end; iResult:=FindNext(SearchRec); end; FindClose(SearchRec); end; procedure TForm1.DoFile(const Folder: TFolder; const FileName: string); function getCN(s:string):string; var i:Integer; tmp:string; begin Result:=''''; i:=Pos('#',s); while i>0 do begin tmp:=Copy(s,1,i - 1); Delete(s,1,i); Result:=Result + WideChar(StrToInt(tmp)); i:=Pos('#',s); end; Result:=Result + WideChar(StrToInt(s)) + ''''; end; var _File:TextFile; Line:string; i:Integer; AFile:TCNFile; _Line:TFileLine; LineNum:Integer; s:string; begin if not Assigned(Folder) then Exit; AssignFile(_File,FileName); AFile:=Folder.Add; AFile.Name:=FileName; LineNum:=0; try Reset(_File); while not Eof(_File) do begin Inc(LineNum); Readln(_File,Line); for i:=1 to Length(Line) do begin if (Ord(Line[i]) > 127) then begin AFile.HashCN:=True; _Line:=AFile.Add; _Line.Line:=LineNum; _Line.Context:=Line; Break; end else if (Line[i] = '#') then begin AFile.HashCN:=True; _Line:=AFile.Add; _Line.Line:=LineNum; s:=Copy(Line,i + 1,MaxInt); _Line.Context:=Copy(Line,1,i - 1) + getCN(s); Break; end; end; end; finally CloseFile(_File); end; end; procedure TForm1.MakeTree; procedure AddFile(const Node:TTreeNode;const Folder:TFolder); var i:Integer; _File:TCNFile; _Node:TTreeNode; begin for i:=0 to Folder.Count - 1 do begin _File:=TCNFile(Folder.Files[i]); if cb_CN.Checked then if not _File.HashCN then Continue; _Node:=TreeView1.Items.AddChild(Node,ExtractFileName(_File.Name)); _Node.Data:=_File; if _File.HashCN then begin _Node.ImageIndex:=1; _Node.SelectedIndex:=1; end else begin _Node.ImageIndex:=2; _Node.SelectedIndex:=2; end; end; end; procedure AddFolder(const Parent:TTreeNode;const Folder:TFolder); var i:Integer; _Folder:TFolder; _Node:TTreeNode; begin _Node:=TreeView1.Items.AddChild(Parent,Folder.Name); _Node.ImageIndex:=0; _Node.SelectedIndex:=0; // _Node.Data:=Folder; AddFile(_Node,Folder); for i:=0 to Folder.FolderCount - 1 do begin _Folder:=TFolder(Folder.Folders[i]); AddFolder(_Node,_Folder); end; _Node.Expand(True); end; begin // TreeView1.Items.BeginUpdate; AddFolder(nil,Root); // TreeView1.Items.EndUpdate; end; procedure TForm1.WaitFor; begin Screen.Cursor:=crHourGlass; // Sleep(100); while ThreadCount > 0 do begin OutputDebugString(PChar('== ' + IntToStr(ThreadCount))); Sleep(10); end; stProgress.Percent:=0; MakeTree; Screen.Cursor:=crDefault; end; procedure TForm1.ThreadEnd(sender: TObject); begin Dec(ThreadCount); end; { TCNFile } function TCNFile.Add: TFileLine; begin Result:=TFileLine.Create; if not Assigned(FContexts) then FContexts:=TObjectList.Create; FContexts.Add(Result); end; destructor TCNFile.destroy; begin if Assigned(FContexts) then FContexts.Free; end; function TCNFile.GetContexts(const Index: integer): TFileLine; begin Result:=nil; if Index in [0..Count-1] then Result:=TFileLine(FContexts.Items[Index]); end; function TCNFile.GetCount: Integer; begin Result:= -1 ; if Assigned(FContexts) then Result:=FContexts.Count; end; { TFolder } function TFolder.Add: TCNFile; begin FCS.Enter; Result:=TCNFile.Create; if not Assigned(FFiles) then FFiles:=TObjectList.Create; FFiles.Add(Result); FCS.Leave; end; function TFolder.AddFoler: TFolder; begin Result:=TFolder.Create; if not Assigned(FFolders) then FFolders:=TObjectList.Create; FFolders.Add(Result); end; constructor TFolder.Create; begin FCS:=TCriticalSection.Create; end; destructor TFolder.Destroy; begin if Assigned(FFiles) then FFiles.Free; if Assigned(FFolders) then FFolders.Free; FCS.Free; inherited; end; function TFolder.GetCount: Integer; begin Result:= -1 ; if Assigned(FFiles) then Result:=FFiles.Count; end; function TFolder.GetFiles(const Index: integer): TCNFile; begin Result:=nil; if Index in [0..Count-1] then Result:=TCNFile(FFiles.Items[Index]); end; procedure TForm1.Button1Click(Sender: TObject); begin TreeView1.Items.Clear; if Assigned(Root) then FreeAndNil(Root); Root:=TFolder.Create; Root.Name:='搜索结果'; SearchProc(Root,edt_Path.Text); WaitFor; end; function TFolder.GetFolderCount: Integer; begin Result:= -1 ; if Assigned(FFolders) then Result:=FFolders.Count; end; function TFolder.GetFolders(const Index: integer): TFolder; begin Result:=nil; if Index in [0..FolderCount-1] then Result:=TFolder(FFolders.Items[Index]); end; { TFileThread } procedure TFileThread.Execute; begin // FreeOnTerminate:=True; if Assigned(FMethod) then FMethod(FFolder,FFileName); end; procedure TForm1.TreeView1Click(Sender: TObject); var item:TTreeNode; i:Integer; _File:TCNFile; _Line:TFileLine; Count:Integer; begin item:=TreeView1.Selected; if FLast = item then Exit; FLast:=item; FCS.Enter; if not Assigned(item) then Exit; if Assigned(item.Data) then begin // if item.Data is TCNFile then begin Memo1.Lines.BeginUpdate; Memo1.Lines.Clear; _File:=TCNFile(item.Data); stText.Caption:=_File.Name; if _File.Count > 50 then Count:=50 else Count:=_File.Count; for i:=0 to Count -1 do begin _Line:=_File.Contexts[i]; Memo1.Lines.Add('行号:' + IntToStr(_Line.Line)); Memo1.Lines.Add(_Line.Context); Memo1.Lines.Add(''); end; Memo1.Lines.EndUpdate; end; end; FCS.Leave; end; procedure TForm1.FormCreate(Sender: TObject); begin FCS:=TCriticalSection.Create; end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin FCS.Free; if Assigned(Root) then Root.Free; end; procedure TForm1.TreeView1DblClick(Sender: TObject); var item:TTreeNode; begin item:=TreeView1.Selected; if not Assigned(item) then Exit; if Assigned(item.Data) then WinExec(PChar('notepad.exe ' + TCNFile(item.Data).Name),SW_SHOW); end; procedure TForm1.edt_PathDblClick(Sender: TObject); var outMsg: string; OldPath,_Path:string; begin outMsg := '选择目录'; OldPath:=edt_Path.Text; _Path := BrowseForFolder(outMsg, OldPath); if _Path = EmptyStr then _Path:=OldPath; edt_Path.Text:=_Path; end; procedure TForm1.cb_CNClick(Sender: TObject); begin TreeView1.Items.BeginUpdate; TreeView1.Items.Clear; MakeTree; TreeView1.Items.EndUpdate; end; procedure TForm1.stTextDblClick(Sender: TObject); var _file:string; begin _file:=stText.Caption; if FileExists(_file) then ShellExecute(Handle,PChar('Open'),PChar(_file),nil,nil,SW_SHOWNORMAL); end; end.
多线程执行长时间的任务,客户端显示出任务的执行进度的示例
更多精彩
赞助商链接