打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
【转】Delphi TSearchRec Attr结构搞不定Windows变态的文件类型!

【转】Delphi TSearchRec Attr结构搞不定Windows变态的文件类型!

在Delphi 中判断一个是文件还是文件夹通常我们会用类似于

(SearchRec.Attr=16) and (SearchRec.Name<>'.' ) and (SearchRec.Name<>'..' ) 之类的屁话来写,虽然搞不定全部,但写了这么多年程序也没有遇到过什么异常情况!

今天遇到一个变态客户安装的XP SP3 竟然找不到文件夹了 查阅了一些网络垃圾才恍然大语!如下:

Delphi中的TSearchRec结构中Attr的属性从帮助文档可知Attr只提供了7中类型的文件属性值:
-------------------------------------------------------------
faReadOnly 1 Read-only files Current user does not have write access.
faHidden 2 Hidden files File name begins with ".".
faSysFile 4 System files File is socket, symbolic link, device file, or FIFO.
faVolumeID 8 Volume ID files Not used.
faDirectory 16 Directory files Directory.
faArchive 32 Archive files Not used.
faSymLink 64 Symbolic link File is a symbolic link.
faAnyFile 71 Any file Any file.
-------------------------------------------------------------
而实际上,Windows中远不只这几种类型的文件。当我们通过判断Attr值来查找制定类型的文件时如

果用以上7中值查找我们会漏掉很多类型的文件,因为很多文件类型TSearchRec.Attr都没有提供,且即便是用faAnyFile或者用这7种类型的组合也不能找出全部的文件。通过分析发现,我还找到了Windows中众多不同于以上7中Value值的文件,现将这些文件类型罗列如下:
-------------------------------------------------------------
1.其中文件夹(即目录)的几种属性组合情况【压缩和加密不可同时存在】
8208 NULL
8208 只读
8210 隐藏
8240 存档
16 索引
10256 压缩
24624 加密

8242 只读+隐藏
8240 只读+存档
16 只读+索引
10256 只读+压缩
24624 只读+加密

8242 只读+隐藏+存档
18 只读+隐藏+索引
10258 只读+隐藏+压缩
24626 只读+隐藏+加密

50 只读+隐藏+存档+索引
10290 只读+隐藏+存档+压缩
24626 只读+隐藏+存档+加密

2098 只读+隐藏+存档+索引+压缩
16434 只读+隐藏+存档+索引+加密

48 只读+存档+索引
10288 只读+存档+压缩
24624 只读+存档+加密

2096 只读+存档+索引+压缩
16432 只读+存档+索引+加密

2096 只读+索引+压缩
16432 只读+索引+加密

8242 隐藏+存档
18 隐藏+索引
10258 隐藏+压缩
24626 隐藏+加密

50 隐藏+存档+索引
10290 隐藏+存档+压缩
24626 隐藏+存档+加密

2098 隐藏+索引+压缩
16434 隐藏+索引+加密

48 存档+索引
10288 存档+压缩
24624 存档+加密

2096 存档+索引+压缩
16432 存档+索引+加密

2096 索引+压缩
16400 索引+加密

文件夹(即目录)可能有以下类型【用对应Value值表示】
16,17,18,19,20,21,22,23,48,49,50,2064,2066,2096,2098,8208,8210,8240,8242,10256,10258,10

288,10290,16400,16402,16432,16434,2462

4,24626,1243048

-------------------------------------------------------------
2.其中文件的几种属性组合情况【此处没有像文件夹类型那样一一写成对应整数值】
只读
隐藏
存档
索引
压缩
加密

只读+隐藏
只读+存档
只读+索引
只读+压缩
只读+加密

只读+隐藏+存档
只读+隐藏+索引
只读+隐藏+压缩
只读+隐藏+加密

只读+隐藏+存档+索引
只读+隐藏+存档+压缩
只读+隐藏+存档+加密

文件可能有以下类型【用对应Value值表示】
1,2,3,4,6,7,32,33,34,35,36,38,39,128,2049,2080,2083,2086,8192,8193,8195,8224,8227,10241

, 12582,16416,16419,

24577,16416,16419, 24577

后记:Windows中的文件大部分都在提供的7种类型中,但是如果我们要搜索文件是硬盘上的所有类

型的文件时用提供的7种类型或其组合是无法找出来的,我们只能通过盘读SearchRec.Attr>0的方式找出所有文件,当我们要查找这7种文件类型以外的某种指定类型的文件时我们只能通过制定其Value来查找。以下提供了几个遍历文件有关的函数或方法:

unit utFileSearch;

interface

uses
Windows, SysUtils, Classes;

{ TODO : 从搜索记录中判断是否是子目录 }
function IsValidDir(SearchRec:TSearchRec):Boolean;

{ TODO : 判断是不是实在的文件 }
function IsRealFile(SearchRec:TSearchRec):Boolean;

{ TODO : 返回所有的文件名及其路径[不包括目录文件]
    MainPath:string; 为根目录
    var FoundResult:TStrings;为返回的文件列表结果集
    当找到的文件大于一个时返回True}
function ListRealFile(MainPath:string; var FoundResult:TStrings):Boolean;

{ TODO : 返回所有的文件夹名及其路径[既目录文件]
    MainPath:string; 为根目录
    var FoundResult:TStrings;为返回的文件列表结果集
    当找到的文件大于一个时返回True}
function ListValidDir(MainPath:string; var FoundResult:TStrings):Boolean;

{ TODO : 遍历指定文件类型的文件名及其路径
    MainPath:string; 为根目录
    FileExt:string; 为需要查找的文件扩展名,必须代点如‘.exe’
    var FoundResult:TStrings;为返回的文件列表结果集
    当找到的文件大于一个时返回True}
function ListExtFile(MainPath:string; FileExt:string; var

FoundResult:TStrings):Boolean;

{ TODO : 获取可写入的磁盘的列表}
function GetDrives(var ResultList:TStrings):integer;

{ TODO : 遍历指定文件类型的文件名及其路径[所有盘符下]
    FileExt:string; 为需要查找的文件扩展名,必须代点如‘.exe’
    var FoundResult:TStrings;为返回的文件列表结果集
    当找到的文件大于一个时返回True}
function ListAllExtFile(FileExt:string; var FoundResult:TStrings):Boolean;

implementation

{将可写入数据的盘罗列出来,抛弃未知,光驱,路径不正确的}
function GetDrives(var ResultList:TStrings):integer;
var
DriveNum: Integer;
DriveBits: set of 0..25; //假设最多有26个盘
DriveType: UINT;          //驱动器类型
DriveName: string;
begin
//获取全部Drivers并格式化到DriveBits里面
Integer(DriveBits) := GetLogicalDrives;
for DriveNum := 0 to 25 do
begin
    //不在表里则放弃
    if not (DriveNum in DriveBits) then Continue;
    DriveName:= Char(DriveNum + Ord('A'))+ ':';
    DriveType:= GetDriveType(PCHAR(@DriveName[1])); //获得磁盘类型
    //清楚CDROM,未知,无效 和 network 类型的驱动器
    if (DriveType<>DRIVE_CDROM) and (DriveType<>0) and
       (DriveType<>DRIVE_REMOTE) and (DriveType<>1) then
    begin
      ResultList.Add(DriveName+'\');
    end;
end;
Result:=ResultList.Count;
end;

function IsValidDir(SearchRec:TSearchRec):Boolean;
begin
{ TODO : 文件类型为[16,31]和48,49,2064,2096的都是文件夹既目录 }
if ( ((SearchRec.Attr>=16)and(SearchRec.Attr<=31))       or
       (SearchRec.Attr=48)    or   (SearchRec.Attr=49)     or
       (SearchRec.Attr=50)    or   (SearchRec.Attr=2064)   or
       (SearchRec.Attr=2066) or   (SearchRec.Attr=2096)   or
       (SearchRec.Attr=2098) or   (SearchRec.Attr=8208)   or
       (SearchRec.Attr=8210) or   (SearchRec.Attr=8240)   or
       (SearchRec.Attr=8242) or   (SearchRec.Attr=10256) or
       (SearchRec.Attr=10258) or   (SearchRec.Attr=10288) or
       (SearchRec.Attr=10290) or   (SearchRec.Attr=16400) or
       (SearchRec.Attr=16402) or   (SearchRec.Attr=16432) or
       (SearchRec.Attr=16434) or   (SearchRec.Attr=24624) or
       (SearchRec.Attr=24626) or   (SearchRec.Attr=1243048) ) and
     ( SearchRec.Name<>'.' ) and (SearchRec.Name<>'..' )
then Result:=True else Result:=False;
end;

function IsRealFile(SearchRec:TSearchRec):Boolean;
begin
{ TODO : 文件类型为1,2,3,4,6,7,32,33,34,35,36,38,39,128,2049,2080,2083,2086,
8192,8193,8195,8224,8227,10241, 12582,16416,16419, 24577的都是实在的文件}
if ( ((SearchRec.Attr>=1)and(SearchRec.Attr<=15)) or //[1,15]
        ((SearchRec.Attr>=32)and(SearchRec.Attr<40)) or //[32,40)
        (SearchRec.Attr=128) or (SearchRec.Attr=2049) or
        (SearchRec.Attr=2080)or (SearchRec.Attr=2083) or
        (SearchRec.Attr=2086)or (SearchRec.Attr=8192) or
        (SearchRec.Attr=8193)or (SearchRec.Attr=8195) or
        (SearchRec.Attr=8224)or (SearchRec.Attr=8227) or
        (SearchRec.Attr=10241)or (SearchRec.Attr=12582) or
        (SearchRec.Attr=16416)or (SearchRec.Attr=16419) or
        (SearchRec.Attr=24577) ) and
     (SearchRec.Name<>'.') and (SearchRec.Name<>'..')
then Result:=True else Result:=False;
end;

function ListRealFile(MainPath:string; var FoundResult:TStrings):Boolean;
var SearchRec:TSearchRec;
    Dir:TStrings;     //用TStrings记录找到的文件的路径
    i:Integer;
begin
    MainPath:=Trim(MainPath);
    if MainPath='' then
    begin
       Result:=False;
       Exit;
    end;
    Dir:=TStringList.Create;
    FindFirst(MainPath+'*.*',faAnyFile, SearchRec);
    //将子目录放入Dir中
    if IsValidDir(SearchRec) then Dir.Add(SearchRec.Name);
    //将文件放入结果集中
    if IsRealFile(SearchRec) then FoundResult.Add(MainPath+SearchRec.Name);
    //找完第一条后继续寻找
    Repeat
      i:=FindNext(SearchRec);
      if i=0 then
      begin
        if IsValidDir(SearchRec) then Dir.Add(SearchRec.Name);
        if IsRealFile(SearchRec) then FoundResult.Add(MainPath+SearchRec.Name);
      end;
    Until i<>0;
    //释放由FindFirst开启的资源
    FindClose(SearchRec);
    //这是递归部分,查找各子目录。
    for i:=0 to Dir.Count-1 do
      ListRealFile(MainPath+Dir.Strings[i]+'\',FoundResult);
    //资源释放
    Dir.Free;
    if FoundResult.Count>0 then Result:=True else Result:=False;
end;

function ListValidDir(MainPath:string; var FoundResult:TStrings):Boolean;
var SearchRec:TSearchRec;
    Dir:TStrings;     //用TStrings记录找到的文件的路径
    i:Integer;
begin
    MainPath:=Trim(MainPath);
    if MainPath='' then
    begin
       Result:=False;
       Exit;
    end;
    Dir:=TStringList.Create;
    FindFirst(MainPath+'*.*',faAnyFile, SearchRec);
    //将递归时还要用的子目录放入Dir中
    if IsValidDir(SearchRec) then
    begin
      Dir.Add(SearchRec.Name);
      //收集结果集
      FoundResult.Add(MainPath+SearchRec.Name);
    end;
    //找完第一条后继续寻找
    Repeat
      i:=FindNext(SearchRec);
      if (i=0) and IsValidDir(SearchRec) then
      begin
        Dir.Add(SearchRec.Name);
        FoundResult.Add(MainPath+SearchRec.Name);
      end;
    Until i<>0;
    //释放由FindFirst开启的资源
    FindClose(SearchRec);
    //这是递归部分,查找各子目录。
    for i:=0 to Dir.Count-1 do
      ListValidDir(MainPath+Dir.Strings[i]+'\',FoundResult);
    //资源释放
    Dir.Free;
    if FoundResult.Count>0 then Result:=True else Result:=False;
end;

function ListExtFile(MainPath:string; FileExt:string; var

FoundResult:TStrings):Boolean;
var SearchRec:TSearchRec;
    Dir:TStrings;     //用TStrings记录找到的文件的路径
    i:Integer;
begin
    MainPath:=Trim(MainPath);
    FileExt:=Trim(FileExt);
    //检查输入合法性
    if (MainPath='') or (FileExt='') then
    begin
       Result:=False;
       Exit;
    end;
    Dir:=TStringList.Create;
    FindFirst(MainPath+'*.*',faAnyFile, SearchRec);
    //将子目录放入Dir中
    if IsValidDir(SearchRec) then Dir.Add(SearchRec.Name);
    //将文件放入结果集中
    if IsRealFile(SearchRec) then
       if ExtractFileExt(SearchRec.Name)=FileExt then
          FoundResult.Add(MainPath+SearchRec.Name);
    //找完第一条后继续寻找
    Repeat
      i:=FindNext(SearchRec);
      if i=0 then
      begin
        if IsValidDir(SearchRec) then Dir.Add(SearchRec.Name);
        if IsRealFile(SearchRec) then
           if ExtractFileExt(SearchRec.Name)=FileExt then
              FoundResult.Add(MainPath+SearchRec.Name);
      end;
    Until i<>0;
    //释放由FindFirst开启的资源
    FindClose(SearchRec);
    //这是递归部分,查找各子目录。
    for i:=0 to Dir.Count-1 do
      ListExtFile(MainPath+Dir.Strings[i]+'\',FileExt,FoundResult);
    //资源释放
    Dir.Free;
    if FoundResult.Count>0 then Result:=True else Result:=False;
end;

function ListAllExtFile(FileExt:string; var FoundResult:TStrings):Boolean;
var SearchRec:TSearchRec;
    Dir,MainDir:TStrings;
    i,j:Integer;

    function GetDrives(var ResultList:TStrings):integer;
    var
      DriveNum: Integer;
      DriveBits: set of 0..25;
      DriveType: UINT;
      DriveName: string;
    begin
      Integer(DriveBits) := GetLogicalDrives;
      for DriveNum := 0 to 25 do
      begin
        if not (DriveNum in DriveBits) then Continue;
        DriveName:= Char(DriveNum + Ord('A'))+ ':';
        DriveType:= GetDriveType(PCHAR(@DriveName[1]));
        if (DriveType<>DRIVE_CDROM) and (DriveType<>0) and
           (DriveType<>DRIVE_REMOTE) and (DriveType<>1) then
        begin
          ResultList.Add(DriveName+'\');
        end;
      end;
      Result:=ResultList.Count;
    end;

begin
    FileExt:=Trim(FileExt);
    if FileExt='' then
    begin
       Result:=False;
       Exit;
    end;
    MainDir:=TStringList.Create;
    if GetDrives(MainDir)>0 then
    begin
      for j:=0 to MainDir.Count-1 do
      begin
        Dir:=TStringList.Create;
        FindFirst(MainDir.Strings[j]+'*.*',faAnyFile, SearchRec);
        if IsValidDir(SearchRec) then Dir.Add(SearchRec.Name);
        if IsRealFile(SearchRec) then
           if ExtractFileExt(SearchRec.Name)=FileExt then
              FoundResult.Add(MainDir.Strings[j]+SearchRec.Name);
        Repeat
          i:=FindNext(SearchRec);
          if i=0 then
          begin
            if IsValidDir(SearchRec) then Dir.Add(SearchRec.Name);
            if IsRealFile(SearchRec) then
               if ExtractFileExt(SearchRec.Name)=FileExt then
                  FoundResult.Add(MainDir.Strings[j]+SearchRec.Name);
          end;
        Until i<>0;
        FindClose(SearchRec);
        for i:=0 to Dir.Count-1 do
          ListExtFile(MainDir.Strings[j]+Dir.Strings[i]+'\',FileExt,FoundResult);
        Dir.Free;
      end;
      if FoundResult.Count>0 then Result:=True else Result:=False;
    end
    else
      Result:=False;
    MainDir.Free;
end;

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
Delphi中关于文件、目录操作的函数
TSearchRec
判断文件夹下子文件夹是否为空
delphi在目录中搜索文件
查找某目录下的所有文件
不同编程语言遍历磁盘所有文件和文件夹实例
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服