2

このJEDIコンポーネントを使用してファイルを列挙していますが、ジャンクションをスキップすることはできません。これを修正するためにできるコードの設定や変更はありますか?

jvsearchfiles.pasユニットの関連するコードを100%確信していません。しかし、私はそれがここにあると思います:

function TJvSearchFiles.EnumFiles(const ADirectoryName: string;
  Dirs: TStrings; const Search: Boolean): Boolean;
var
  Handle: THandle;
  Finished: Boolean;
  DirOK: Boolean;
begin
  DoBeginScanDir(ADirectoryName);

  { Always scan the full directory - ie use * as mask - this seems faster
    then first using a mask, and then scanning the directory for subdirs }
  Handle := FindFirstFile(PChar(ADirectoryName + '*'), FFindData);
  Result := Handle <> INVALID_HANDLE_VALUE;
  if not Result then
  begin
    Result := GetLastError in [ERROR_FILE_NOT_FOUND, ERROR_ACCESS_DENIED];;
    Exit;
  end;

  Finished := False;
  try
    while not Finished do
    begin
      // (p3) no need to bring in the Forms unit for this:
      if not IsConsole then
        DoProgress;
      { After DoProgress, the user can have called Abort,
        so check it }
      if FAborting then
      begin
        Result := False;
        Exit;
      end;

      with FFindData do
        { Is it a directory? }
        if (dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY > 0) then
        begin
          { Filter out '.' and '..'
            Other dir names can't begin with a '.' }

          {                         | Event | AddDir | SearchInDir
           -----------------------------------------------------------------
            doExcludeSubDirs        |
              True                  |   Y       N           N
              False                 |   N       N           N
            doIncludeSubDirs        |
              True                  |   Y       Y           Y
              False                 |   N       Y           Y
            doExcludeInvalidDirs    |
              True                  |   Y       Y           Y
              False                 |   N       Y           N
            doExcludeCompleteInvalidDirs |
              True                  |   Y       Y           Y
              False                 |   N       N           N
          }
          if not IsDotOrDotDot(cFileName) and
            ((soIncludeSystemHiddenDirs in Options) or not IsSystemAndHidden(FFindData)) then
            { Use case to prevent unnecessary calls to DoCheckDir }
            case DirOption of
              doExcludeSubDirs, doIncludeSubDirs:
                begin
                  if Search and (soSearchDirs in Options) and DoCheckDir then
                    DoFindDir(ADirectoryName);
                  if DirOption = doIncludeSubDirs then
                    Dirs.AddObject(cFileName, TObject(True))
                end;
              doExcludeInvalidDirs, doExcludeCompleteInvalidDirs:
                begin
                  DirOK := DoCheckDir;
                  if Search and (soSearchDirs in Options) and DirOK then
                    DoFindDir(ADirectoryName);

                  if (DirOption = doExcludeInvalidDirs) or DirOK then
                    Dirs.AddObject(cFileName, TObject(DirOK));
                end;
            end;
        end
        else
        if Search and (soSearchFiles in Options) and DoCheckFile then
          DoFindFile(ADirectoryName);

      if not FindNextFile(Handle, FFindData) then
      begin
        Finished := True;
        Result := GetLastError = ERROR_NO_MORE_FILES;
      end;
    end;
  finally
    Result := FindClose(Handle) and Result;
  end;
end;

これは前の質問で与えられた機能ですが、私はそれを機能させることができませんでした。

function IsJunction(const FileName: string): Boolean;
const
  IO_REPARSE_TAG_MOUNT_POINT = $0A0000003;
var
  FindHandle: THandle;
  FindData: TWin32FindData;
begin
  Result := False;
  FindHandle := FindFirstFile(PChar(FileName), FindData);
  if FindHandle <> INVALID_HANDLE_VALUE then begin
    Result := ((FindData.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT)
                = FILE_ATTRIBUTE_REPARSE_POINT) and
                ((FindData.dwReserved0 and IO_REPARSE_TAG_MOUNT_POINT)
                = IO_REPARSE_TAG_MOUNT_POINT);
    winapi.windows.FindClose(FindHandle);
  end else
    RaiseLastOSError;
end;
4

1 に答える 1

3

あなたが見ている関数には、すでにディレクトリをスキップするポイントがあります:

if not IsDotOrDotDot(cFileName) and
   ((soIncludeSystemHiddenDirs in Options) or not IsSystemAndHidden(FFindData)) then

したがって、この条件を簡単に拡張できます。andただし、別の句を追加して拡張することはしません。個人的にはif、このような発言は非常に不透明だと思います。説明変数を導入します。

var
  SkipDirectory: Boolean;

次に、次のように割り当てます。

if IsDotOrDotDot(cFileName) then
  SkipDirectory := True
else if IsSystemAndHidden(FFindData) and not (soIncludeSystemHiddenDirs in Options) then
  SkipDirectory := True
else if IsJunction(FFindData) then
  SkipDirectory := True
else
  SkipDirectory := False;

if not SkipDirectory then
  ....

そしてIsJunction、パラメータを受け取るために再加工する必要がありTWin32FindDataます:

function IsJunction(const FindData: TWin32FindData): Boolean;
const
  IO_REPARSE_TAG_MOUNT_POINT = $0A0000003;
begin
  Result := ((FindData.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT)
              = FILE_ATTRIBUTE_REPARSE_POINT) and
              (FindData.dwReserved0 = IO_REPARSE_TAG_MOUNT_POINT);
end;

おそらく @Sertac の if ステートメントを書き直して、もう少し分割したいと思います。しかし、おそらくそれは私の個人的な好みです。

function FlagIsSet(Flags, Flag: DWORD): Boolean;
begin
  Result := (Flags and Flag)<>0;
end;

function IsJunction(const FindData: TWin32FindData): Boolean;
const
  IO_REPARSE_TAG_MOUNT_POINT = $0A0000003;
begin
  Result := FlagIsSet(FindData.dwFileAttributes, FILE_ATTRIBUTE_REPARSE_POINT)
            and (FindData.dwReserved0=IO_REPARSE_TAG_MOUNT_POINT);
end;
于 2012-11-18T10:14:18.003 に答える