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

어떤 버전의 델파이입니까? –

+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

코드가 잘 작동합니다, 감사합니다 Logged – XXXXXXXXXXXXXX