A+

通过WIN32_FIND_DATA遍历文件及子目录

2019年04月10日 系统集成 1条评论 466次浏览

在说这篇文章之前先说说WIN32_FIND_DATA,它是一个C/C++的数据结构,关于C++的代码百度搜索这个数据结构可以得到一大堆的代码,我不懂C++,但是我可以用autoit调用这个数据结构来实现相同的结果。

关于WIN32_FIND_DATA的数据结构详细说明请百度搜索,我这里主要说的是怎么用autoit调用这个数据结构。

在autoit里可以通过DllStructCreate函数创建C/C++数据结构,然后再使用DllStructGetData函数返回数据结构的元素数据,有了这两个函数,我们基本就可以直接调用WIN32_FIND_DATA了。

在写代码之前,先来介绍一下AU3里的另外几个自定义函数

_WinAPI_FindFirstFile:它是搜索匹配特定名称的文件或子目录的名称,成功则返回搜索句柄,这个函数包括两个参数值,

$sFilePath:目录或路径和文件名, 可以包括通配符, 例如星号 "*" 或问号 "?" 如果字符串以通配符, 句号 "." 或目录名结尾, 用户必须有根和路径上所有子目录的访问权限

$tData:接收找到的文件或目录信息的 $tagWIN32_FIND_DATA 结构指针

_WinAPI_FindNextFile:它是继续搜索文件或目录的自定义函数,返回值成功则返回一个bool值true。

$hSearch:先前调用 _WinAPI_FindFirstFile() 函数返回的搜索句柄

$tData:接收找到的文件或目录信息的 $tagWIN32_FIND_DATA 结构指针

_WinAPI_FindClose:关闭文件搜索句柄,成功返回一个bool值true。

$hSearch:由 _WinAPI_FindFirst... 函数打开的文件搜索句柄

好了,知道这些函数的运用,我们就可以着手来写代码了,首先创建一个自定义函数,AU3的创建格式是:

  1. Func _function()
  2. EndFunc

给自定义函数添加一个参数值变量:$file

  1. Func _function($file)
  2. EndFunc

接下来开始在自定义函数里写代码添加功能。

  1. Func _function($file)
  2.     Local $aList[101]
  3.     Local $tData = DllStructCreate($tagWIN32_FIND_DATA)
  4.     Local $sFile
  5.     Local $hSearch = _WinAPI_FindFirstFile($file$tData)
  6.     While Not @error
  7.         $sFile = DllStructGetData($tData, 'cFileName')
  8.         Switch $sFile
  9.             Case '.''..'
  10.             Case Else
  11.                 If Not BitAND(DllStructGetData($tData, 'dwFileAttributes'), $FILE_ATTRIBUTE_DIRECTORY) Then
  12.                     $aList[0] += 1
  13.                     If $aList[0] > UBound($aList) - 1 Then
  14.                         ReDim $aList[UBound($aList) + 100]
  15.                     EndIf
  16.                     $aList[$aList[0]] = $sFile
  17.                 EndIf
  18.         EndSwitch
  19.         _WinAPI_FindNextFile($hSearch$tData)
  20.     WEnd
  21.     _WinAPI_FindClose($hSearch)
  22.     Return $aList
  23. EndFunc

以上代码就是获取指定路径的自定义函数,运用得函数也就是上面我们提到过的几个函数,简单说一下吧。

首先我们需要创建一个一维数组$aList,定义数组的初始成员数为101个(当然成员数101个有的时候肯定是不够的,比如system32文件夹里的文件就绝对不够,但我们后面的代码会调整数组的成员数。),接着使用 DllStructCreate函数调用WIN32_FIND_DATA数据结构,然后开始利用_WinAPI_FindFirstFile函数搜索文件句柄,最后开始循环搜索。

说一下下面代码的意思吧,它能告诉你返回的元素类型是不是文件夹,所以我们加上了一个if else语句来判断,if 不是文件夹就返回元素,当然如果要同时获取文件夹的话就不需要这个判断了。

  1. If Not BitAND(DllStructGetData($tData, 'dwFileAttributes'), $FILE_ATTRIBUTE_DIRECTORY) Then

如果只是想获取文件夹,那代码就是:

  1. If BitAND(DllStructGetData($tData, 'dwFileAttributes'), $FILE_ATTRIBUTE_DIRECTORY) Then

最后来说说怎么调用这个自定义函数吧,刚才我们有在自定义函数里添加了一个参数值,现在来告诉你参数值是干嘛的吧,其实它是一个指定搜索路径的变量,这个变量用在了这里      

  1. Local $hSearch = _WinAPI_FindFirstFile($file$tData)

而自定义函数里最后我把数组变量返回了。

  1. Return $aList

$aList是一个数组变量,返回给function($file)这个自定义函数,而$file是搜索句柄的指定路径。

那么意思是说其实function($file)返回的值就是一个数组变量,而数组的成员其实就是function($file)[0]。

接下来就开始调用这个自定义函数获取数据。

可以使用for next循环来枚举搜索结构,假设我们要获取windows目录下的所有文件,代码如下:

  1. For $i = 1 To _function(@WindowsDir & "\*")[0]
  2.     MsgBox(0, 0, _function(@WindowsDir & "\*")[$i])
  3. Next

总结:

其实autoit的系统函数也可以获取到文件及子目录,比如:

  1. #include <MsgBoxConstants.au3>
  2. Example()
  3. Func Example()
  4.     Local $hSearch = FileFindFirstFile("*.*")
  5.     If $hSearch = -1 Then
  6.         MsgBox($MB_SYSTEMMODAL"""Error: No files/directories matched the search pattern.")
  7.         Return False
  8.     EndIf
  9.     Local $sFileName = ""$iResult = 0
  10.     While 1
  11.         $sFileName = FileFindNextFile($hSearch)
  12.         If @error Then ExitLoop
  13.         $iResult = MsgBox(BitOR($MB_SYSTEMMODAL$MB_OKCANCEL), """File: " & $sFileName)
  14.         If $iResult <> $IDOK Then ExitLoop
  15.     WEnd
  16.     FileClose($hSearch)
  17. EndFunc

缺点是搜索太慢,而使用WIN32_FIND_DATA搜索效率就要快很多,所以推荐那些需要写相关功能的朋友好好看一下这篇文章。

  • 本文为原创文章,版权归所有。欢迎分享本文,转载请保留出处!
  • 给我留言

    评论列表 (有 466 次浏览 和 1 条评论)
    1. 回复 城南花已开

      嘿嘿,好东西,赶紧收藏了