2013-07-31 80 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