打开APP
userphoto
未登录

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

开通VIP
获得一个目录下的文件名

 ;要获得一个目录下的全部文件名,通常使用 FindFirstFile 和 FindNextFile 这两个API。具体的做法可想而知:先用前者找到一下,然后再用后者找下一个直到找不到… …除此之外,还有通过DOS命令DIR获得指定目录下的目录列表,然后一个个的拆出来的方法,这种方法过于麻烦,今天要实现的是使用API的 ^_^

先对这些API做个简单的介绍:

FindFirstFile Function

HANDLE WINAPI FindFirstFile(
__in LPCTSTR lpFileName,
__out LPWIN32_FIND_DATA lpFindFileData
);
Parameters
lpFileName 指向一个字符串,代表要寻找的文件名。
lpFindFileData 指向一个缓冲区,函数会在缓冲区中返回一个WIN32_FIND_DATA结构
Return Value
如果成功,会返回一个handle 可以给FindNextFile或者 FindClose使用
如果失败,返回INVALID_HANDLE_VALUE。
WIN32_FIND_DATA Structure
typedef struct _WIN32_FIND_DATA {
                          DWORD dwFileAttributes; 找到的文件的属性
                           FILETIME ftCreationTime; 创建日期
                           FILETIME ftLastAccessTime;最后访问日期
                          FILETIME ftLastWriteTime; 最后写入日期
                           DWORD nFileSizeHigh; 文件长度的高32位
                          DWORD nFileSizeLow; 文件长度的低32位
                           DWORD dwReserved0; 扩展的文件标记
                            DWORD dwReserved1; 保留
                             TCHAR cFileName[MAX_PATH];本次找到的文件名
                             TCHAR cAlternateFileName[14]; 文件的8.3文件名
} WIN32_FIND_DATA,
*PWIN32_FIND_DATA,
*LPWIN32_FIND_DATA;

其中,文件的大小计算方法: (nFileSizeHigh * (MAXDWORD+1)) + nFileSizeLow.

DWORD dwReserved0; 扩展的文件标记,之前一直定义为未使用,而在目前的MSDN上说明为"If the dwFileAttributes member includes the FILE_ATTRIBUTE_REPARSE_POINT attribute, this member specifies the reparse point tag."看起来好像是能否返回文件的所属类型。

cFileName 中只有文件名称,不包括路径。

FindNextFile Function

BOOL WINAPI FindNextFile(
__in HANDLE hFindFile,
__out LPWIN32_FIND_DATA lpFindFileData
);

Parameters
hFindFile FindFirstFile或者FindFirstFileEx返回的handle
lpFindFileData 和FindFirstFile的一样,用来返回找到的文件信息

Return Value
If the function succeeds, the return value is nonzero.
If the function fails, the return value is zero (0). To get extended error information, call GetLastError.
If no matching files can be found, the GetLastError function returns ERROR_NO_MORE_FILES.

 
#Mode=CON

   .386
   .model flat, stdcall
   option casemap :none

   include windows.inc
   include user32.inc
   include kernel32.inc
   include masm32.inc

   includelib user32.lib
   includelib kernel32.lib
   includelib masm32.lib
   include macro.asm
   .data
      szStartPath   db   'c:\windows',0
      szFilter      db   '*.exe',0
      szEnter      db   10,13,0
      
   .data?
      buffer      db 100 dup(?)
      dwCounter   dd   ?
   .CODE
   ProcessFile   proc
         ret
   ProcessFile Endp

   FindFile   proc   lpszPath
         local   stFindFile:WIN32_FIND_DATA
         local   hFindFile
         ;MAX_PATH在Windows.inc中有定义=260,注意大小写
         local   szPath[MAX_PATH]     :byte   ;当前要搜索的路径
         local   szSearch[MAX_PATH]  :byte   ;当前要搜索的路径\*.dll
         local   szFindFile[MAX_PATH]:byte   ;路径\找到的文件
         
         pushad
         invoke   lstrcpy,addr szPath,lpszPath   ;生成当前要搜索的路径
         
         @@:
         invoke   lstrlen,addr szPath
         lea      esi,szPath
         add      esi,eax         ;指向 szPath 中最后一个字符
         xor      eax,eax
         mov      al,'\'
         .if   BYTE ptr [esi-1] != al  ;判断最后一个字符的前一个字符是否为 \
                  mov   word ptr [esi],ax  ;不是,补全 szPath的形式就是 db 'xxxx\',0
         .endif
         
         invoke   lstrcpy,addr   szSearch,addr   szPath   ;复制到 szSearch
         invoke   lstrcat,addr   szSearch,addr   szFilter ;szSearch 的形式就是 db 'xxxx\*.dll',0
         
         invoke   FindFirstFile,addr   szSearch,addr   stFindFile
         .if      eax != INVALID_HANDLE_VALUE
               mov   hFindFile,eax                     ;保存查找的handle
               .repeat
      invoke   lstrcpy,addr   szFindFile,addr   szPath ;因为找到的文件是不带路径
                                     ;所以,结果上要补全路径
      invoke   lstrcat,addr   szFindFile,addr   stFindFile.cFileName  ;加上找到的文件名
               .if      stFindFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
                                    ;找到的是目录
                  .if   stFindFile.cFileName != '.'         ;如果找到的目录不是"."
                  invoke FindFile,addr   szFindFile      ;递归,进入这个目录
               .endif
               .else      ;找到的不是目录,就是文件
                  inc    dwCounter               ;文件计数器加一
                  invoke StdOut,addr   szFindFile      ;输出文件名
                  invoke StdOut,addr   szEnter
               .endif
                  ;继续在这个目录中查找
                  invoke   FindNextFile,hFindFile,addr   stFindFile              .until   (eax==FALSE)      ;直到找不到满足条件的文件
                 invoke   FindClose,hFindFile
         .endif        
         popad
         ret
   FindFile   endp

   START:
      mov      dwCounter,0
      invoke   FindFile,addr   szStartPath         ;起始路径
      invoke   wsprintf,addr buffer,CTXT("%s %d %s"),CTXT('一共找到'),dwCounter,CTXT('个文件')
      invoke    StdOut,addr buffer
      
      ;暂停显示,回车键关闭
      invoke StdIn,addr buffer,sizeof buffer
      invoke ExitProcess,0
      
   end START
 
(编辑注:这段程序上的排版有些问题,建议读者拷贝到MasmPlus中查看,根据自动的逻辑划分体式可以很清晰的看懂结构)上面的程序参考了《Windows环境下32位汇编语言程序设计》,其中的核心部分
 invoke FindFirstFile,addr szSearch,addr stFindFile
.if eax != INVALID_HANDLE_VALUE
mov hFindFile,eax ;保存查找的handle
.repeat
invoke lstrcpy,addr szFindFile,addr szPath ;因为找到的文件是不带路径
;所以,结果上要补全路径
invoke lstrcat,addr szFindFile,addr stFindFile.cFileName ;加上找到的文件名
.if stFindFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ;找到的是目录
.if stFindFile.cFileName != '.' ;如果找到的目录不是"."
invoke FindFile,addr szFindFile ;递归,进入这个目录
.endif
.else ;找到的不是目录,就是文件
inc dwCounter ;文件计数器加一
invoke StdOut,addr szFindFile ;输出文件名
invoke StdOut,addr szEnter
.endif
;继续在这个目录中查找
invoke FindNextFile,hFindFile,addr stFindFile .until (eax==FALSE) ;直到找不到满足条件的文件

使用了递归,注意这个地方:
.if stFindFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY 
用来判断找到的是否为目录,如果是,则进入递归,如果不是,则在下面按照文件的方式处理。但是这里面包含了一个小小的问题:如果我的目录名称满足通配符,会找到,但是因为它不是文件,可能会被漏掉。

举例说明,我在Windows目录下使用md lll.exe 建立一个名称为 "lll.exe"的目录。使用dir *.exe命令,结果如下:
 
 
 
而使用我们的程序,结果却是:略
 
解决方法是
 .if stFindFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ;找到的是目录?
.if stFindFile.cFileName != '.' ;如果找到的目录不是"."
****在这个地方或者下一跳代码的后面进行处理
invoke FindFile,addr szFindFile ;递归,进入这个目录
.endif
.else ;找到的不是目录,就是文件
...
.endif
另外,试验中发现:如果你使用非 "*.*"的通配符查找,是无法找到目录的。意思是如果你打算用这种方法"查找给定的路径下面的包括子目录的所有满足条件的文件",是不行的。




   
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
随机数的产生原理与实现
实战串行通讯
用汇编写系统服务程序
双进程保护
学 Win32 汇编[3]: 控制台下的几种输出方式
【新提醒】修改硬盘MBR引导区(Windows各系统通用),Win32汇编语言案例解析,典型案例解析(VIP免费),鱼C论坛
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服