2013-07-31 226 views
0

我投降,我花了我近12小時的時間來得到我想要的,但我不能。排除搜索文件夾和文件

此代碼搜索所有文件夾和文件名,但我想排除一些文件夾,包括我想從搜索中排除的文件夾的子目錄。

我希望有人可以提供幫助。

procedure TForm1.CombineDir(InDir : string; OutStream : TStream); 
var AE : TArchiveEntry; 
    dFound:boolean; 

    procedure RecurseDirectory(ADir : string); 
    var sr : TSearchRec; 
     TmpStream : TStream; 
    begin 
    if FindFirst(ADir + '*', faAnyFile, sr) = 0 then begin 
     repeat 
     if (sr.Attr and (faDirectory or faVolumeID)) = 0 then begin 
      //ShowMessage('Filename is :>'+ ADir + sr.Name); 
      if (NotThisPath.IndexOf(ADir + sr.Name)>=0) or dFound then begin 
      ShowMessage('DO NOT INCLUDE THIS FILENAME :>'+ ADir + sr.Name); 
      end else begin 
      ShowMessage('>>> INCLUDE THIS FILENAME :>'+ ADir + sr.Name); 
      // We have a file (as opposed to a directory or anything 
      // else). Write the file entry header. 
      AE.EntryType := aeFile; 
      AE.FileNameLen := Length(sr.Name); 
      AE.FileLength := sr.Size; 
      OutStream.Write(AE, SizeOf(AE)); 
      OutStream.Write(sr.Name[1], Length(sr.Name)); 
      // Write the file itself 
      TmpStream := TFileStream.Create(ADir + sr.Name, fmOpenRead or fmShareDenyWrite); 
      OutStream.CopyFrom(TmpStream, TmpStream.Size); 
      TmpStream.Free; 
      end; 
     end; 

     if (sr.Attr and faDirectory) > 0 then begin 
      if (sr.Name <> '.') and (sr.Name <> '..') then begin 
      //ShowMessage('DIR is:>'+ ADir + sr.Name); 
      //if (Pos(ADir, NotThisPath.Text)>0) then 
      if (NotThisPath.IndexOf(ADir + sr.Name)>=0) then begin 
       ShowMessage('DO NOT INCLUDE THIS DIR:>'+ ADir + sr.Name); 
       dFound:=True; 
      end else begin 
       ShowMessage('>>> INCLUDE THIS DIR:>'+ ADir + sr.Name); 
       // Write the directory entry 
       AE.EntryType := aeDirectory; 
       AE.DirNameLen := Length(sr.Name); 
       OutStream.Write(AE, SizeOf(AE)); 
       OutStream.Write(sr.Name[1], Length(sr.Name)); 
      end; 
      // Recurse into this directory 
      RecurseDirectory(IncludeTrailingPathDelimiter(ADir + sr.Name)); 
      end; 
     end; 
     until FindNext(sr) <> 0; 
     FindClose(sr); 
    end; 
    // Show that we are done with this directory 
    AE.EntryType := aeEOD; 
    OutStream.Write(AE, SizeOf(AE)); 
    end; 

begin 
RecurseDirectory(IncludeTrailingPathDelimiter(InDir)); 
end; 

NotThisPath是一個TStringList;

+1

你應該小心謹慎地格式化你的代碼 - 如果格式不好,那麼沒有人會閱讀它。 –

+1

Delphi的哪個版本? –

+0

德爾福7,而不是德爾福XEs – XXXXXXXXXXXXXX

回答

5

我認爲你的根本問題是你已經將文件枚舉,文件名過濾和你的GUI混合在一起,變成了一個邪惡的傻瓜。你根本不應該看到從表單的方法調用FindFirst。調用FindFirst的代碼屬於助手類或函數。

我不會試圖直接回答你的問題,尤其是因爲你沒有真正提出問題。我要嘗試的是向您展示如何區分枚舉文件和過濾名稱的問題。

首先,我要實現這個功能:

procedure EnumerateFiles(Dir: string; 
    const EnumerateFileName: TEnumerateFileNameMethod); 

此功能在Dir參數傳遞的目錄,並將其進行枚舉目錄中的所有文件,其子目錄,等遞歸。找到的每個文件都傳遞給回調方法EnumerateFileName。這被定義,像這樣:

type 
    TEnumerateFileNameMethod = procedure(const FileName: string) of object; 

的實現是很簡單的。這只是基於標準FindFirst的重複循環。該功能拒絕特殊目錄...。它會緩存到它遇到的任何目錄中。

procedure EnumerateFiles(Dir: string; 
    const EnumerateFileName: TEnumerateFileNameMethod); 
var 
    SR: TSearchRec; 
begin 
    Dir := IncludeTrailingPathDelimiter(Dir); 
    if FindFirst(Dir + '*', faAnyFile, SR) = 0 then 
    try 
     repeat 
     if (SR.Name = '.') or (SR.Name = '..') then 
      continue; 
     if (SR.Attr and faDirectory) <> 0 then 
      EnumerateFiles(Dir + SR.Name, EnumerateFileName) 
     else 
      EnumerateFileName(Dir + SR.Name); 
     until FindNext(SR) <> 0; 
    finally 
     FindClose(SR); 
    end; 
end; 

現在,這應該是足夠簡單,以遵循我的希望。下一個問題是過濾。你可以在你提供的回調方法中實現它。下面是一個完整的演示,演示如何使用.pas擴展選擇Delphi源文件。

program EnumerateFilesDemo; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils; 

type 
    TEnumerateFileNameMethod = procedure(const FileName: string) of object; 

procedure EnumerateFiles(Dir: string; 
    const EnumerateFileName: TEnumerateFileNameMethod); 
var 
    SR: TSearchRec; 
begin 
    Dir := IncludeTrailingPathDelimiter(Dir); 
    if FindFirst(Dir + '*', faAnyFile, SR) = 0 then 
    try 
     repeat 
     if (SR.Name = '.') or (SR.Name = '..') then 
      continue; 
     if (SR.Attr and faDirectory) <> 0 then 
      EnumerateFiles(Dir + SR.Name, EnumerateFileName) 
     else 
      EnumerateFileName(Dir + SR.Name); 
     until FindNext(SR) <> 0; 
    finally 
     FindClose(SR); 
    end; 
end; 

type 
    TDummyClass = class 
    class procedure EnumerateFileName(const FileName: string); 
    end; 

class procedure TDummyClass.EnumerateFileName(const FileName: string); 
begin 
    if SameText(ExtractFileExt(FileName), '.pas') then 
    Writeln(FileName); 
end; 

procedure Main; 
begin 
    EnumerateFiles('C:\Users\heff\Development', TDummyClass.EnumerateFileName); 
end; 

begin 
    try 
    Main; 
    Readln; 
    except 
    on E: Exception do 
     Writeln(E.ClassName, ': ', E.Message); 
    end; 
end. 

現在,我知道這不是你想要做的篩選類型,但問題是,我們現在有普遍性。您可以使用任何您想要的過濾來將呼叫替換爲SameText。一旦你選擇了你想要處理的文件,你就可以做你喜歡的文件。

爲了方便起見,我使用了類方法。我不希望我的演示用實例化對象的樣板來裝載。但是爲了您的需要,您希望創建一個類來處理枚舉回調。該類將封裝您正在執行的文件歸檔操作。該類將擁有輸出流的一個實例。回調方法將是一個寫入存檔的實例方法。

現在,我還沒有爲您的問題實施完整的解決方案,但我希望我已經做得更好。即向您展示如何分解代碼以簡化解決問題的過程。

+0

更好,謝謝 – XXXXXXXXXXXXXX

+0

該代碼工作正常,謝謝 – XXXXXXXXXXXXXX