本类文章的标签为 ‘Excel对象模型’

Page 1 of 3123

使用VBA操作文件(12):如何使用VBA查找文件

1 颗星2 颗星3 颗星4 颗星5 颗星 (1 人投票, 平均: 5.00 out of 5)
Loading ... Loading ...

下面的代码主要介绍如何使用Windows API函数及内置的VBA函数查找和列出文件。当然,VBA也包含了用于查找和列出文件的Application.FileSearch对象。
方法1:使用Windows API
步骤1 在VBE中,插入一个标准模块,并输入下面的代码:

Declare Function FindFirstFile Lib "kernel32" Alias _
   "FindFirstFileA" (ByVal lpFileName As String, lpFindFileData _
   As WIN32_FIND_DATA) As Long
 
   Declare Function FindNextFile Lib "kernel32" Alias "FindNextFileA" _
   (ByVal hFindFile As Long, lpFindFileData As WIN32_FIND_DATA) As Long
 
   Declare Function GetFileAttributes Lib "kernel32" Alias _
   "GetFileAttributesA" (ByVal lpFileName As String) As Long
 
   Declare Function FindClose Lib "kernel32" (ByVal hFindFile As Long) _
   As Long
 
   Declare Function FileTimeToLocalFileTime Lib "kernel32" _
   (lpFileTime As FILETIME, lpLocalFileTime As FILETIME) As Long
 
   Declare Function FileTimeToSystemTime Lib "kernel32" _
   (lpFileTime As FILETIME, lpSystemTime As SYSTEMTIME) As Long
 
   Public Const MAX_PATH = 260
   Public Const MAXDWORD = &HFFFF
   Public Const INVALID_HANDLE_VALUE = -1
   Public Const FILE_ATTRIBUTE_ARCHIVE = &H20
   Public Const FILE_ATTRIBUTE_DIRECTORY = &H10
   Public Const FILE_ATTRIBUTE_HIDDEN = &H2
   Public Const FILE_ATTRIBUTE_NORMAL = &H80
   Public Const FILE_ATTRIBUTE_READONLY = &H1
   Public Const FILE_ATTRIBUTE_SYSTEM = &H4
   Public Const FILE_ATTRIBUTE_TEMPORARY = &H100
 
   Type FILETIME
     dwLowDateTime As Long
     dwHighDateTime As Long
   End Type
 
   Type WIN32_FIND_DATA
     dwFileAttributes As Long
     ftCreationTime As FILETIME
     ftLastAccessTime As FILETIME
     ftLastWriteTime As FILETIME
     nFileSizeHigh As Long
     nFileSizeLow As Long
     dwReserved0 As Long
     dwReserved1 As Long
     cFileName As String * MAX_PATH
     cAlternate As String * 14
   End Type
 
   Type SYSTEMTIME
     wYear As Integer
     wMonth As Integer
     wDayOfWeek As Integer
     wDay As Integer
     wHour As Integer
     wMinute As Integer
     wSecond As Integer
     wMilliseconds As Integer
   End Type
 
   Public Function StripNulls(OriginalStr As String) As String
      If (InStr(OriginalStr, Chr(0)) > 0) Then
         OriginalStr = Left(OriginalStr, _
          InStr(OriginalStr, Chr(0)) - 1)
      End If
      StripNulls = OriginalStr
   End Function

步骤2 在VBE中插入一个用户窗体,如下图所示。
searchfilessample1
如图所示,在用户窗体中,放置4个文本框(分别名为TextBox1、TextBox2、TextBox3、TextBox4),1个命令按钮(名为CommandButton1),1个列表框(名为ListBox1)。
步骤3 在用户窗体代码模块中,添加下列代码:

Function FindFilesAPI(path As String, SearchStr As String, _
    FileCount As Integer, DirCount As Integer)
   Dim FileName As String   ' Walking filename variable...
   Dim DirName As String    ' SubDirectory Name
   Dim dirNames() As String ' Buffer for directory name entries
   Dim nDir As Integer   ' Number of directories in this path
   Dim i As Integer      ' For-loop counter...
   Dim hSearch As Long   ' Search Handle
   Dim WFD As WIN32_FIND_DATA
   Dim Cont As Integer
   Dim FT As FILETIME
   Dim ST As SYSTEMTIME
   Dim DateCStr As String, DateMStr As String
 
   If Right(path, 1) <> "\" Then path = path & "\"
   ' Search for subdirectories.
   nDir = 0
   ReDim dirNames(nDir)
   Cont = True
   hSearch = FindFirstFile(path & "*", WFD)
   If hSearch <> INVALID_HANDLE_VALUE Then
      Do While Cont
         DirName = StripNulls(WFD.cFileName)
         ' Ignore the current and encompassing directories.
         If (DirName <> ".") And (DirName <> "..") Then
            ' Check for directory with bitwise comparison.
            If GetFileAttributes(path & DirName) And _
             FILE_ATTRIBUTE_DIRECTORY Then
               dirNames(nDir) = DirName
               DirCount = DirCount + 1
               nDir = nDir + 1
               ReDim Preserve dirNames(nDir)
               ' Uncomment the next line to list directories
               'List1.AddItem path & FileName
            End If
         End If
         Cont = FindNextFile(hSearch, WFD)  ' Get next subdirectory.
      Loop
      Cont = FindClose(hSearch)
   End If
 
   ' Walk through this directory and sum file sizes.
   hSearch = FindFirstFile(path & SearchStr, WFD)
   Cont = True
   If hSearch <> INVALID_HANDLE_VALUE Then
      While Cont
         FileName = StripNulls(WFD.cFileName)
            If (FileName <> ".") And (FileName <> "..") And _
              ((GetFileAttributes(path & FileName) And _
               FILE_ATTRIBUTE_DIRECTORY) <> FILE_ATTRIBUTE_DIRECTORY) Then
            FindFilesAPI = FindFilesAPI + (WFD.nFileSizeHigh * _
             MAXDWORD) + WFD.nFileSizeLow
            FileCount = FileCount + 1
            ' To list files w/o dates, uncomment the next line
            ' and remove or Comment the lines down to End If
            'List1.AddItem path & FileName
            
           ' Include Creation date...
           FileTimeToLocalFileTime WFD.ftCreationTime, FT
           FileTimeToSystemTime FT, ST
           DateCStr = ST.wMonth & "/" & ST.wDay & "/" & ST.wYear & _
              " " & ST.wHour & ":" & ST.wMinute & ":" & ST.wSecond
           ' and Last Modified Date
           FileTimeToLocalFileTime WFD.ftLastWriteTime, FT
           FileTimeToSystemTime FT, ST
           DateMStr = ST.wMonth & "/" & ST.wDay & "/" & ST.wYear & _
              " " & ST.wHour & ":" & ST.wMinute & ":" & ST.wSecond
           ListBox1.AddItem path & FileName & vbTab & _
              Format(DateCStr, "mm/dd/yyyy hh:nn:ss") _
              & vbTab & Format(DateMStr, "mm/dd/yyyy hh:nn:ss")
          End If
         Cont = FindNextFile(hSearch, WFD)  ' Get next file
      Wend
      Cont = FindClose(hSearch)
   End If
 
   ' If there are sub-directories...
    If nDir > 0 Then
      ' Recursively walk into them...
      For i = 0 To nDir - 1
        FindFilesAPI = FindFilesAPI + FindFilesAPI(path & dirNames(i) _
         & "\", SearchStr, FileCount, DirCount)
      Next i
   End If
   End Function
 
   Private Sub CommandButton1_Click()
       Dim SearchPath As String, FindStr As String
       Dim FileSize As Long
       Dim NumFiles As Integer, NumDirs As Integer
 
       ListBox1.Clear
       SearchPath = TextBox1.Text
       FindStr = TextBox2.Text
       FileSize = FindFilesAPI(SearchPath, FindStr, NumFiles, NumDirs)
       TextBox3.Text = NumFiles & " Files found in " & NumDirs + 1 & _
             " Directories"
       TextBox4.Text = "Size of files found under " & SearchPath & " = " & _
       Format(FileSize, "#,###,###,##0") & " Bytes"
   End Sub

步骤4 测试运行,如下图所示。
searchfilessample2
方法2:使用内置的VBA函数
步骤1 在上例所示的界面中添加2个文本框(TextBox5用于报告搜索到多少个文件,TextBox6用于报告搜索到的文件总的大小),1个列表框(ListBox2用于列出搜索到的文件)。
步骤2 在用户窗体模块中添加下列代码:

Function FindFiles(path As String, SearchStr As String, _
       FileCount As Integer, DirCount As Integer)
      Dim FileName As String   ' Walking filename variable.
      Dim DirName As String    ' SubDirectory Name.
      Dim dirNames() As String ' Buffer for directory name entries.
      Dim nDir As Integer      ' Number of directories in this path.
      Dim i As Integer         ' For-loop counter.

      On Error GoTo sysFileERR
      If Right(path, 1) <> "\" Then path = path & "\"
      ' Search for subdirectories.
      nDir = 0
      ReDim dirNames(nDir)
      DirName = Dir(path, vbDirectory Or vbHidden Or vbArchive Or vbReadOnly _
Or vbSystem)  ' Even if hidden, and so on.
      Do While Len(DirName) > 0
         ' Ignore the current and encompassing directories.
         If (DirName <> ".") And (DirName <> "..") Then
            ' Check for directory with bitwise comparison.
            If GetAttr(path & DirName) And vbDirectory Then
               dirNames(nDir) = DirName
               DirCount = DirCount + 1
               nDir = nDir + 1
               ReDim Preserve dirNames(nDir)
               'List2.AddItem path & DirName ' Uncomment to list
            End If                           ' directories.
sysFileERRCont:
         End If
         DirName = Dir()  ' Get next subdirectory.
      Loop
 
      ' Search through this directory and sum file sizes.
      FileName = Dir(path & SearchStr, vbNormal Or vbHidden Or vbSystem _
      Or vbReadOnly Or vbArchive)
      While Len(FileName) <> 0
         FindFiles = FindFiles + FileLen(path & FileName)
         FileCount = FileCount + 1
         ' Load List box
         ListBox2.AddItem path & FileName & vbTab & _
            FileDateTime(path & FileName)   ' Include Modified Date
         FileName = Dir()  ' Get next file.
      Wend
 
      ' If there are sub-directories..
      If nDir > 0 Then
         ' Recursively walk into them
         For i = 0 To nDir - 1
           FindFiles = FindFiles + FindFiles(path & dirNames(i) & "\", _
            SearchStr, FileCount, DirCount)
         Next i
      End If
 
AbortFunction:
      Exit Function
sysFileERR:
      If Right(DirName, 4) = ".sys" Then
        Resume sysFileERRCont ' Known issue with pagefile.sys
      Else
        MsgBox "Error: " & Err.Number & " - " & Err.Description, , _
         "Unexpected Error"
        Resume AbortFunction
      End If
      End Function
 
Private Sub CommandButton2_Click()
    Dim SearchPath As String, FindStr As String
    Dim FileSize As Long
    Dim NumFiles As Integer, NumDirs As Integer
 
    ListBox2.Clear
    SearchPath = TextBox1.Text
    FindStr = TextBox2.Text
    FileSize = FindFiles(SearchPath, FindStr, NumFiles, NumDirs)
    TextBox5.Text = NumFiles & " Files found in " & NumDirs + 1 & _
       " Directories"
    TextBox6.Text = "Size of files found under " & SearchPath & " = " & _
          Format(FileSize, "#,###,###,##0") & " Bytes"
End Sub
 
Private Sub userForm_Initialize()
    CommandButton1.Caption = "使用API代码"
    CommandButton2.Caption = "使用VBA代码"
    ' start with some reasonable defaults
    TextBox1.Text = "C:\Documents and Settings\m\My Documents"
    TextBox2.Text = "*.*"
End Sub

步骤3 测试代码,如下图所示。
searchfilessample3

示例下载:

方法3:使用VBA文件系统对象
此方法可以参考前面的一系列文章。

注:本文整理自Microsoft知识库,将部分VB代码转换为VBA代码,并给出了详细的示例文档。

相关文章

使用VBA操作文件(11):处理文件、文件夹和驱动器的VBA技术和技巧

1 颗星2 颗星3 颗星4 颗星5 颗星 (1 人投票, 平均: 5.00 out of 5)
Loading ... Loading ...

如果希望处理文件或文件系统,有几种选择可用。最好的选择取决于您希望完成什么任务。可用的选择包括使用VBA函数、Microsoft Scripting Runtime对象库、FileSearch对象,以及与文件系统相关的Windows API函数。
使用VBA函数
可以使用许多VBA函数处理文件系统,下表对这些函数进行了总结。

VBA函数或语句 说明
Dir 返回与指定的格式或文件属性相匹配的文件、目录或文件夹的名称。
GetAttr 返回文件、目录或文件夹的属性。
SetAttr 指定文件、目录或文件夹的属性。
CurDir 返回当前目录。
ChDir 修改当前目录。
ChDrive 修改当前驱动器。
MkDir 创建一个新目录。
RmDir 移除一个现有的目录。
Kill 删除一个或多个文件。
FileLen 以字节返回磁盘中文件的长度。
LOF 以字节返回一个打开文件的长度。
FileCopy 复制磁盘中的文件。
FileDateTime 返回文件创建或最后修改的日期和时间。
Name 重命名文件并将其移动到磁盘中另一个位置。
Open 打开磁盘中的文件来读取或写入。
Input 从打开的文件中读取字符。
Print 写文本到顺序文件中。
Write 写文本到顺序文件中。
Close 关闭使用Open语句打开的文件。


如何使用Dir函数判断某文件是否存在?
Dir函数返回在pathname参数中指定的文件的名称。通常使用Dir函数来判断是否指定的文件存在,例如下面的DoesFileExist函数:

Function DoesFileExist(strFileSpec As String) As Boolean
    ' 如果参数strFileSpec指定的文件存在则返回True.
    ' 如果strFileSpec不是有效的文件或者是一个目录则返回False.
    Const INVALID_ARGUMENT As Long = 53
    On Error GoTo DoesfileExist_Err
    If (GetAttr(strFileSpec) And vbDirectory) <> vbDirectory Then
        DoesFileExist = CBool(Len(Dir(strFileSpec)) > 0)
    Else
        DoesFileExist = False
    End If
DoesfileExist_End:
    Exit Function
DoesfileExist_Err:
    DoesFileExist = False
    Resume DoesfileExist_End
End Function

本例中,GetAttr函数用于确保strFileSpec参数中的值不是一个目录。这是因为,如果向Dir函数中传递一个有效的目录名称,那么将返回在该目录中找到的第一个文件。
如何使用Dir函数获取文件夹中所有文件的名称?
如果pathname参数包含文件夹的路径而不是文件夹中某文件的名称,那么Dir函数返回在该文件夹中找到的第一个文件的名称。接着,再调用Dir函数而无需任何参数,获取文件夹中后面每一个文件的名称。例如,下面的过程返回一个数组,包含在strDirPath参数中指定的目录内所有文件的名称:

Function GetAllFilesInDir(ByVal strDirPath As String) As Variant
    ' 遍历strDirPath中指定的目录并在数组中保存每个文件名
   ' 然后返回该数组到调用过程.
    ' 如果strDirPath不是一个有效的目录则返回False.
    Dim strTempName As String
    Dim varFiles() As Variant
    Dim lngFileCount As Long
 
    On Error GoTo GetAllFiles_Err
 
    ' 确保strDirPath以"\"字符结尾.
    If Right$(strDirPath, 1) <> "\" Then
        strDirPath = strDirPath & "\"
    End If
 
    ' 确保strDirPath是一个目录.
    If GetAttr(strDirPath) = vbDirectory Then
        strTempName = Dir(strDirPath, vbDirectory)
        Do Until Len(strTempName) = 0
            ' 排除 ".", "..".
            If (strTempName <> ".") And (strTempName <> "..") Then
                ' 确保没有子目录名称.
                If (GetAttr(strDirPath & strTempName) _
                    And vbDirectory) <> vbDirectory Then
                    ' 增加数组的大小以适应发现的文件名并将其添加到数组.
                    ReDim Preserve varFiles(lngFileCount)
                    varFiles(lngFileCount) = strTempName
                    lngFileCount = lngFileCount + 1
                End If
            End If
            ' 使用Dir函数查找下一个文件名.
            strTempName = Dir()
        Loop
        ' 返回包含已找到的文件名称的数组.
        GetAllFilesInDir = varFiles
    End If
GetAllFiles_End:
    Exit Function
GetAllFiles_Err:
    GetAllFilesInDir = False
    Resume GetAllFiles_End
End Function

GetAllFilesInDir函数通过遍历目录中的每一项,并且对于发现的文件,将其名称添加到数组。第一次调用Dir时,使用目录名作为其参数。每增加一次调用都使用不带参数的Dir函数。该过程使用GetAttr函数来确保strDirPath参数包含一个有效的目录,也避免任何子目录的名称被添加到数组中。注意,该过程筛选出“.”和“..”,代表当前目录和父目录。
可以使用下面的过程测试GetAllFilesInDir过程。可以对strDirName参数试不同的值,然后使用F8逐行运行代码,看该过程是如何工作的。

Sub TestGetAllFiles()
    Dim varFileArray As Variant
    Dim lngI As Long
    Dim strDirName As String
 
    Const NO_FILES_IN_DIR As Long = 9
    Const INVALID_DIR As Long = 13
 
    On Error GoTo Test_Err
 
    strDirName = "c:\my documents"
    varFileArray = GetAllFilesInDir(strDirName)
    For lngI = 0 To UBound(varFileArray)
        Debug.Print varFileArray(lngI)
    Next lngI
 
Test_Err:
    Select Case Err.Number
        Case NO_FILES_IN_DIR
            MsgBox "The directory named '" & strDirName _
                & "' contains no files."
        Case INVALID_DIR
            MsgBox "'" & strDirName & "' is not a valid directory."
        Case 0
        Case Else
            MsgBox "Error #" & Err.Number & " - " & Err.Description
    End Select
End Sub

使用Microsoft Scripting Runtime Object Library
Microsoft Scripting Runtime对象库包含可以用于操作文件和目录的对象,并且比前面讲述的VBA函数更容易使用。
在使用该对象库之前,必须设置对该对象库的引用。如果在“引用”对话框中没有找到该对象库,那么应该可以在C:\Windows\System子文件夹中找到它(Scrrun.dll)。
下表描述了Scripting Runtime对象库是的对象。

对象 集合 描述
Dictionary 顶层对象,与VBA Collection集合对象相似。
Drive Drives 引用系统中的驱动器或驱动器的集合。
File Files 引用文件系统中的文件或文件集合。
FileSystemObject 顶层对象,用于访问驱动器、文件夹、文件。
Folder Folders 引用文件系统中的文件夹或文件夹集合。
TextStream 引用读取、写入或追加到文本文件中的一系列文本。


在Scripting Runtime对象库中的顶层对象是Dictionary对象和FileSystemObject对象。要使用Dictionary对象,则需创建一个Dictionary类型的对象变量,然后设置其为Dictionary对象的新实例。

Dim dctDict As Scripting.Dictionary
Set dctDict = New Scripting.Dictionary

要在代码中使用Scripting Runtime库中的其它对象,必须首先创建FileSystemObject类型的变量,然后使用New关键词创建该FileSystemObject对象的新实例,如下面的代码所示:

Dim fsoSysObj As Scripting.FileSystemObject
Set fsoSysObj = New Scripting.FileSystemObject

接着使用这个引用FileSystemObject对象的变量来处理Drive、Folder、File和TextStream对象。
如何使用FileSystemObject对象来处理文件和文件夹?
一旦创建了FileSystemObject对象的新实例,就能够使用它来处理驱动器、文件夹和文件了。
下面的过程返回特定文件夹中的文件到Dictionary对象里。GetFiles过程接受三个参数:目录路径、Dictionary对象、一个可选的布尔参数,指定是否应该递归调用该过程。该过程返回一个布尔值,指明是否过程运行成功。
该过程首先使用GetFolder方法返回对Folder对象的引用,然后遍历该文件夹的Files集合,添加每个文件的文件名称和路径到Dictionary对象中。如果blnRecursive参数设置为True,那么GetFiles过程被递归调用以返回每个子文件夹中的文件。

Function GetFiles(strPath As String, _
                dctDict As Scripting.Dictionary, _
                Optional blnRecursive As Boolean) As Boolean
 
   ' 本过程返回目录中的所有文件到Dictionary对象中.
   ' 如果递归调用则同时返回子文件夹中的所有文件.
   
   Dim fsoSysObj      As Scripting.FileSystemObject
   Dim fdrFolder      As Scripting.Folder
   Dim fdrSubFolder   As Scripting.Folder
   Dim filFile        As Scripting.File
 
   ' 返回新的FileSystemObject.
   Set fsoSysObj = New Scripting.FileSystemObject
 
   On Error Resume Next
   ' 获取文件夹.
   Set fdrFolder = fsoSysObj.GetFolder(strPath)
   If Err <> 0 Then
      ' 不正确的路径.
      GetFiles = False
      GoTo GetFiles_End
   End If
   On Error GoTo 0
 
   ' 遍历Files集合,添加到字典.
   For Each filFile In fdrFolder.Files
      dctDict.Add filFile.Path, filFile.Path
   Next filFile
 
   ' 如果Recursive标志为真,则递归调用.
   If blnRecursive Then
      For Each fdrSubFolder In fdrFolder.SubFolders
         GetFiles fdrSubFolder.Path, dctDict, True
      Next fdrSubFolder
   End If
 
   ' 如果没有错误发生则返回True.
   GetFiles = True
 
GetFiles_End:
   Exit Function
End Function
 
   ' 如果没有错误发生则返回True.
   GetFiles = True
 
GetFiles_End:
   Exit Function
End Function

可以使用下面的过程来测试GetFiles过程。该过程创建一个新Dictionary对象,将其传递到GetFiles过程,然后在立即窗口中打印在strDirPath目录及其子目录中的每个文件。

Sub TestGetFiles()
   ' 测试GetFiles函数.

   Dim dctDict As Scripting.Dictionary
   Dim varItem As Variant
   Dim strDirPath As String
 
   strDirPath = "c:\my documents\"
   ' 创建新的字典.
   Set dctDict = New Scripting.Dictionary
   ' 递归调用, 返回文件到Dictionary对象.
   If GetFiles(strDirPath, dctDict, True) Then
      ' 打印字典中的项目.
      For Each varItem In dctDict
         Debug.Print varItem
      Next
   End If
End Sub

可以对strDirPath参数试验不同的值,看看该过程是如何工作的。
如何使用FileSystemObject来处理文件属性?
File对象和Folder对象提供了Attributes属性,可用来读取或设置文件或文件夹的属性,如下面的示例。
ChangeFileAttributes过程接受四个参数:文件夹的路径、指定要设置的属性的可选的常量、指定要移除的属性的可选常量、指定是否递归调用过程的可选的参数。
如果传递的文件夹路径是有效的,那么该过程返回Folder对象。接着检查是否提供了lngSetAttr参数,如果是,那么该过程遍历文件夹中的所有文件,追加新的属性到每个文件现有的属性中。对于lngRemoveAttr参数做同样的事情,在本例中,如果指定的属性存在于集合中的文件内则移除。
最后,该过程检查blnRecursive参数是否被设置为True,如果是则为strPath参数指定的每个子文件夹中的每个文件调用该过程。

Function ChangeFileAttributes(strPath As String, _
                            Optional lngSetAttr As FileAttribute, _
                            Optional lngRemoveAttr As FileAttribute, _
                            Optional blnRecursive As Boolean) As Boolean
 
   ' 本函数接受一个目录路径, 一个指定文件属性设置的值
   ' 一个指定文件属性移除的值
   ' 一个指明是否递归调用的标志
   ' 如果没有发生错误则返回True.
   
   Dim fsoSysObj      As Scripting.FileSystemObject
   Dim fdrFolder      As Scripting.Folder
   Dim fdrSubFolder   As Scripting.Folder
   Dim filFile        As Scripting.File
 
   ' 返回新的FileSystemObject.
   Set fsoSysObj = New Scripting.FileSystemObject
 
   On Error Resume Next
   ' 获取文件夹.
   Set fdrFolder = fsoSysObj.GetFolder(strPath)
   If Err <> 0 Then
      ' 不正确的路径.
      ChangeFileAttributes = False
      GoTo ChangeFileAttributes_End
   End If
   On Error GoTo 0
 
   ' 如果调用者传递属性去设置则设置所有的.
   If lngSetAttr Then
      For Each filFile In fdrFolder.Files
         If Not (filFile.Attributes And lngSetAttr) Then
            filFile.Attributes = filFile.Attributes Or lngSetAttr
         End If
      Next
   End If
 
   ' 如果调用者传递属性去移除则移除所有的.
   If lngRemoveAttr Then
      For Each filFile In fdrFolder.Files
         If (filFile.Attributes And lngRemoveAttr) Then
            filFile.Attributes = filFile.Attributes - lngRemoveAttr
         End If
      Next
   End If
 
   ' 如果调用者设置blnRecursive参数为True,则递归调用函数.
   If blnRecursive Then
      ' 遍历子文件夹.
      For Each fdrSubFolder In fdrFolder.SubFolders
         ' 调用带有子文件夹路径的函数.
         ChangeFileAttributes fdrSubFolder.Path, lngSetAttr, _
            lngRemoveAttr, True
      Next
   End If
   ChangeFileAttributes = True
 
ChangeFileAttributes_End:
   Exit Function
End Function

可以使用下面的过程测试ChangeFileAttributes过程。在本例中,具有隐藏属性设置的“我的文档”文件夹中的所有文件被设置可见:

Sub TestChangeAttributes()
    If ChangeFileAttributes("c:\my documents", , _
        Hidden, False) = True Then
        MsgBox "File attributes succesfully changed!"
    End If
End Sub

可以对ChangefileAttributes过程中的参数试验不同的值,看看该过程是如何工作的。
使用FileSearch对象
FileSearch对象是Microsoft Office 9.0 Object Library中的一个成员,公开了Office文件打开对话框的所有功能的编程接口,包括在高级查找对话框中的功能。可以使用FileSearch对象的对象、方法和属性基于提供的条件来搜索文件或文件集合。
下面的示例展示了如何使用FileSearch驿象查找在strFilespec参数中指定类型的一个和多个文件。注意,通过分号分隔符指定扩展名列表可以搜索多个文件扩展名:

Function CustomFindFile(strFileSpec As String)
    ' 本过程演示一个简单的文件搜索程序
    ' 显示一个消息框,包含在"C:\"目录中与参数strFileSpec提供的文件规范相匹配的所有文件的名称
    ' 参数strFileSpec可以包含一个或多个在分号分隔列表中的文件规格.
    ' 例如,下面的strFileSpec参数返回"c:\"中包含扩展名"*.log;*.bat;*.ini"的包有文件
    
   Dim fsoFileSearch   As Office.FileSearch
    Dim varFile         As Variant
    Dim strFileList     As String
 
    ' 如果输入有效,那么处理文件搜索.
    If Len(strFileSpec) >= 3 And InStr(strFileSpec, "*.") > 0 Then
        Set fsoFileSearch = Application.FileSearch
        With fsoFileSearch
            .NewSearch
            .LookIn = "c:\"
            .Filename = strFileSpec
            .SearchSubFolders = False
            If .Execute() > 0 Then
                For Each varFile In .FoundFiles
                    strFileList = strFileList & varFile & vbCrLf
                Next varFile
            End If
        End With
        MsgBox strFileList
    Else
        MsgBox strFileSpec & " is not a valid file specification."
        Exit Function
    End If
End Function

FileSearch对象有两个方法和一些属性,可用于在自定义的Office解决方案中创建自定义文件搜索功能。上述示例使用NewSearch方法清除任何以前的搜索条件,Execute方法执行搜索特定的文件。Execute方法返回找到的文件数,同时支持可选的参数来指定排序顺序、排序类型、以及是否用来仅保存快速搜索索引来执行搜索。使用FoundFiles属性返回对FoundFiles对象的引用(FoundFiles对象包含搜索中找到的所有匹配文件的名称)。
使用LookIn属性指定搜索的目录,使用SearchSubFolders属性指定是否搜索在LookIn属性指定的目录中的子文件夹。FileName属性支持通配符和文件名或文件类型规范的分号分隔列表。

注:本文初译自MSDN:Working with Files, Folders, and Drives: More VBA Tips and Tricks,辑录于此,作为文件操作应用大全的一部分。

相关文章

使用VBA操作文件(10):SearchFolders集合

1 颗星2 颗星3 颗星4 颗星5 颗星 (目前还没有人投票)
Loading ... Loading ...

本文主要介绍如何使用SearchFolders集合搜索文件。
介绍
在Office 9.0类型库中的FileSearch对象允许编程搜索匹配条件(例如作者的名字、文件的类型、最后修改文件的日期,等)的文件。此外,可以缩小搜索条件到已知的文件夹及任何子文件夹。然而,如果不知道路径的话,就没有方法搜索文件夹。
在Office 10.0类型库中添加到FileSearch对象的SearchFolders集合允许编程搜索多个文件夹中的文件,即便不知道它们的路径。
探索创建搜索条件的对象模型
为了更好地理解如何编程创建搜索条件,下图显示了可以使用的各种集合和对象,下表描述了SearchFolders集合及其子对象的用途。
filesearchobjectmodel1
图:FileSearch对象模型
表:SearchFolders集合及其子对象

对象/集合 用途
SearchFolders 代表要通过使用FileSearch对象搜索的文件夹集合。每个应用程序仅有一个SearchFolders集合。可以添加一个或多个ScopeFolder对象到该SearchFolders集合。
ScopeFolder 代表希望添加到搜索的文件夹或子文件夹。每个ScopeFolder对象可以包含0个或多个ScopeFolders对象(子文件夹的集合)。如果ScopeFolder对象没有相应的子ScopeFolder对象的ScopeFolders集合,意味着该文件夹没有子文件夹(但该文件夹可以包含文件)。
ScopeFolders 代表属于父ScopeFolder对象的一个或多个子文件夹的集合。


其它搜索对象简介

  • FileTypes集合 (Office XP中新增) 代表能够搜索的一个或多个文件类型(例如,Microsoft Excel文件或Microsoft PowerPoint文件)。在一个应用程序中仅有一个FileTypes集合。调用FileSearch对象的NewSearch方法清除FileTypes集合中任何以前的设置(例如,Application.FileSearch.NewSearch)。
  • FoundFiles集合 代表文件搜索返回的0个或多个文件。可以使用For Each…Next循环与FoundFiles集合一起,对查找的每个文件采取某种操作,例如打开或打印。等价于搜索结果任务窗格中呈现的文件列表。调用FileSearch对象的Execute方法开始文件搜索,更新FoundFiles集合(例如,Application.FileSearch.Execute)。
  • PropertyTests集合 代表应用到基本搜索的一个或多个高级搜索条件。等价于在高级搜索任务窗格的搜索区中呈现的结果。
  • SearchScopes集合(Office XP新增) 代表可以搜索的可用的本地或网络计算机资源 (例如,我的电脑,网上邻居,或Microsoft Outlook)。不能够从SearchScopes集合中添加或删除SearchScope对象等价于选择搜索任务窗格中的搜索框。

示例:搜索文件夹中包含指定文本的文件
示例下载:

本示例演示了SearchFolders集合如何工作。在示例中,当用户选择Word文档中的一些文本,并通过自定义用户窗体提供文件夹名后,代码搜索用户计算机中与用户提供的文件夹名相匹配的包含所选文本的任何文件,然后使用自定义用户窗体报告匹配文件的列表。
在搜索之前,应该清除任何以前的搜索条件。ClearPreviousSearchFolders过程通过从SearchFolders中移除任何存在的SearchFolder对象来完成这项操作。此外,该过程设置LookIn属性为空字符串,并调用NewSearch方法重设所有剩余的搜索条件为其默认设置。
为了搜索用户计算机上所有的文件夹,使用了递归的SearchForSubFolders过程。如果没有这个过程,那么搜索条件将仅限于用户计算机上文件夹的第一层。SearchForSubFolders过程调用其本身多次以遍历计算机整个目录结构。每次该过程找到与用户提供的文件夹名称相匹配的文件夹名后,调用AddToSearchFolders方法添加文件夹到应用程序的SearchFolders集合。
遍历用户计算机的整个目录结构之后,通过SearchFolders集合搜索包含用户所选文本的任何文件。FileSearch对象的Execute方法,与PropertyTests集合的LookIn属性和Add方法一起,返回包含相匹配文件的FoundFiles集合,通过调用ReportResultsToUser过程来更新和显示用户窗体报告给用户。
小结
SearchFolders集合允许编程搜索多个文件夹中的文件,即便事先不知道其路径。因为SearchFolders集合是FileSearch对象的一部分,可以容易地合并其它搜索条件到搜索解决方案中。

注:本文初译自MSDN:Using the SearchFolders Collection,收录于此,作为文件操作大全的一部分。

相关文章

使用VBA操作文件(9):应用示例

1 颗星2 颗星3 颗星4 颗星5 颗星 (目前还没有人投票)
Loading ... Loading ...

下面是在vbaepress中使用VBA操控文件的一些示例代码,供参考。
选择文件并打开
不知道要打开的文件的具体位置,通过用户选择后打开该文件。

Sub GetOpenFileNameExample3()
    Dim lCount As Long
    Dim vFilename As Variant
    Dim sPath As String
    Dim lFilecount As Long
    sPath = "c:\windows\temp\"
    ChDrive sPath
    ChDir sPath
    vFilename = Application.GetOpenFilename("Microsoft Excel files (*.xls),*.xls", , "Please select the file(s) to open", , True)
    If TypeName(vFilename) = "Boolean" Then Exit Sub
    For lCount = 1 To UBound(vFilename)
        Workbooks.Open vFilename(lCount)
    Next
End Sub

如果要选择打开图片文件,则将文件类型改为:

"Image files (*.jpg),*.jpg"

搜索文件
搜索指定目录中含有关键词的所有文件并打开这些文件。

Sub OpenBooksInFolder()
 
    Dim FileFound As String, N As Long
    Dim Sheet As Worksheet, FilePath As String
 
     'stipulate the folders path here
    FilePath = "C:\Documents and Settings\m\桌面"
 
    DoEvents
    Application.ScreenUpdating = False
 
     'list all the books in the folder
    With Application.FileSearch
        .LookIn = FilePath
        .FileType = msoFileTypeExcelWorkbooks
 
         'this should gives partial matches
         'i.e. anything with 'happy' in the
         'name regardless of case
        .Filename = "水工"
 
         'false = only search given folder
        .SearchSubFolders = False
 
        On Error Resume Next
        If .Execute > 0 Then
            For N = 1 To .FoundFiles.Count
 
                 'Debug.Print .FoundFiles(N) '< make a choice
                Workbooks.Open (.FoundFiles(N)) '< make a choice
                 
                 'now do what you want to do
                 'with each open workbook
                 
            Next N
        Else
            MsgBox "The file " & .Filename & " was not found"
        End If
    End With
    Application.ScreenUpdating = True
End Sub

基于文件名将文件移到相应的文件夹中
有许多文件,现在希望根据文件名将该文件移至相应的文件夹。例如,将名称中包含“Bankhill”的文件移到“Bankhill”文件夹,名称中包含“Lite”的文件移到“Lite”文件夹,等等。

Sub LoopFolder()
    Const SourceFolder As String = "C:\Users\ianlane\Desktop\test bucket\"
    Dim oFSO
    Dim oFolder As Object
    Dim oFile As Object
    Dim NewFolder As String
 
    Set oFSO = CreateObject("Scripting.FileSystemObject")
 
    Set oFolder = oFSO.GetFolder(SourceFolder)
 
    For Each oFile In oFolder.Files
 
        If oFile.Type Like "*Comma Separated Values*" Then
            Select Case True
            Case oFile Like "*Bankhill*"
                NewFolder = "Bankhill\"
            Case oFile Like "*Lite*"
                NewFolder = "Lite\"
                 'etc
            End Select
            Name oFile.Path As SourceFolder & NewFolder & oFile.Name
        End If
    Next oFile
 
    Set oFolder = Nothing
    Set oFSO = Nothing
 
End Sub

从FTP中下载文件

' The posting by Billkamm at http://www.dailydoseofexcel.com/archives/2006/01/29/ftp-via-vba/
 ' http://www.access-programmers.co.uk/forums/attachment.php?attachmentid=13389&d=1145948437
 ' http://msdn2.microsoft.com/en-us/library/aa383996.aspx
 ' http://msdn2.microsoft.com/en-us/library/aa384363(VS.85).aspx
 ' http://msdn2.microsoft.com/en-us/library/aa384180(VS.85).aspx
 ' http://msdn2.microsoft.com/en-us/library/aa384157(VS.85).aspx
 ' http://msdn2.microsoft.com/en-us/library/aa384166(VS.85).aspx
 ' http://www.devx.com/getHelpOn/10MinuteSolution/20373/1763
 
 
 ' Open the Internet object
Private Declare Function InternetOpen Lib "wininet.dll" Alias "InternetOpenA" _
(ByVal sAgent As String, ByVal lAccessType As Long, ByVal sProxyName As String, _
ByVal sProxyBypass As String, ByVal lFlags As Long) As Long
 
 ' Connect to the network
Private Declare Function InternetConnect Lib "wininet.dll" Alias "InternetConnectA" _
(ByVal hInternetSession As Long, ByVal sServerName As String, _
ByVal nServerPort As Integer, ByVal sUsername As String, _
ByVal sPassword As String, ByVal lService As Long, _
ByVal lFlags As Long, ByVal lContext As Long) As Long
 
 ' Get a file using FTP
Private Declare Function FtpGetFile Lib "wininet.dll" Alias "FtpGetFileA" _
(ByVal hFtpSession As Long, ByVal lpszRemoteFile As String, _
ByVal lpszNewFile As String, ByVal fFailIfExists As Boolean, _
ByVal dwFlagsAndAttributes As Long, ByVal dwFlags As Long, _
ByVal dwContext As Long) As Boolean
 
 ' Send a file using FTP
Private Declare Function FtpPutFile Lib "wininet.dll" Alias "FtpPutFileA" _
(ByVal hFtpSession As Long, ByVal lpszLocalFile As String, _
ByVal lpszRemoteFile As String, ByVal dwFlags As Long, _
ByVal dwContext As Long) As Boolean
 
 ' Close the Internet object
Private Declare Function InternetCloseHandle Lib "wininet.dll" _
(ByVal hInet As Long) As Integer
 
Sub GetORD_TXT()
 
     ' This sub uses the above functions to get a particular text file stored on the NOAA servers.  (It is the aviation
     ' weather report for Chicago O'Hare.)  This is very basic "proof of concept" code to demonstrate to myself that
     ' the above functions work (they do!) and what I need to be doing when I call them.
     '
     ' This routine will get the KORD.TXT file from the NOAA server and place it in the C:\ directory on my computer.
     '
     ' I've commented out the uninteresting MsgBox lines; they show long (and meaningless) numbers.
     '
     
    Dim AgentStr As String
    Dim AccessTypeLong As Long
    Dim ProxyNameStr As String
    Dim ProxyBypassStr As String
    Dim FlagsLong As Long
 
    Dim InternetSessionLong As Long
    Dim ServerNameStr As String
    Dim ServerPortInt As Integer
    Dim UserNameStr As String
    Dim PasswordStr As String
    Dim ServiceLong As Long
    Dim ContextLong As Long
 
    Dim FTPSessionLong As Long
    Dim RemoteFileStr As String
    Dim NewFileStr As String
    Dim FailIfExistsBool As Boolean
    Dim FlagsAndAttributesLong As Long
 
    Dim SomeThingLong As Long
    Dim MyInternetHandleLong As Long
    Dim MyFTPHandleLong As Long
    Dim SomeInteger As Integer
    Dim FTPSuccessBool As Boolean ' Did the FTP download work?
     
     ' ********************************
     ' **                            **
     ' **  Call INTERNET OPEN first  **
     ' **                            **
     ' ********************************
     
    AgentStr = "GreenTreeTest" ' can be whatever
    AccessTypeLong = 0 ' zero appears to work fine
    ProxyNameStr = "" ' nul works fine here
    ProxyBypassStr = "" ' nul works fine here
    FlagsLong = 0 ' zero appears to work fine
     
    MyInternetHandleLong = InternetOpen(AgentStr, AccessTypeLong, ProxyNameStr, ProxyBypassStr, FlagsLong)
 
     ' MsgBox MyInternetHandleLong
     
 
     ' *********************************
     ' **                             **
     ' **  Call Internet CONNECT next **
     ' **                             **
     ' *********************************
     
     ' The file I want to get is at ftp://tgftp.nws.noaa.gov/data/observations/metar/stations/KORD.TXT
     
     'MyInternetHandleLong is obtained above
    ServerNameStr = "tgftp.nws.noaa.gov" ' address of the FTP server, WITHOUT the "ftp://" part
    ServerPortInt = 21 ' default FTP port
    UserNameStr = "anonymous" ' "anonymous" is the is the default
    PasswordStr = "" ' nul is the default
    ServiceLong = 1 ' this for the FTP service (2 = gopher, 3 = http)
    FlagsLong = 0 ' 0 appears to work fine here
    ContextLong = 0 ' 0 appears to work fine here
     
    MyFTPHandleLong = InternetConnect(MyInternetHandleLong, ServerNameStr, ServerPortInt, UserNameStr, PasswordStr, ServiceLong, FlagsLong, ContextLong)
 
     ' MsgBox "My FTP handle = " & MyFTPHandleLong
     ' (this is NOT the same value as MyInternetHandle, above)
     
 
     ' *****************************
     ' **                         **
     ' **  Call FTP Get File next **
     ' **                         **
     ' *****************************
     
     ' MyFTPHandleLong is obtained above
    RemoteFileStr = "/data/observations/metar/stations/KORD.TXT" ' file name on server, including directories
    NewFileStr = "C:\KORD.txt" ' file name on MY system
    FailIfExistsBool = False ' should NOT fail if file already exists on MY computer.... HOWEVER,
     '  if the file does exist, the FTP DOES fail.  Don't know about this.  Short answer:
     '  the target file should NOT exist on my computer before calling this routine!
    FlagsAndAttributesLong = 128 ' Normal file, no special flags set.
    FlagsLong = 2 ' FTP Transfer Type Binary (the default)
    ContextLong = 0 ' apparently not required.
     
 
    FTPSuccessBool = FtpGetFile(MyFTPHandleLong, RemoteFileStr, NewFileStr, FailIfExistsBool, FlagsAndAttributesLong, FlagsLong, ContextLong)
 
    MsgBox "FTP Success = " & FTPSuccessBool
 
     ' ************************************
     ' **                                **
     ' **  Finally, close the connection **
     ' **                                **
     ' ************************************
     
 
    SomeInteger = InternetCloseHandle(MyInternetHandleLong)
 
     ' MsgBox SomeInteger
     ' Seems to return "1"
     
 
End Sub

相关文章

使用VBA操作文件(8):使用WSH进行其他操作

1 颗星2 颗星3 颗星4 颗星5 颗星 (目前还没有人投票)
Loading ... Loading ...

WSH使得操作任何安装在计算机上的自动化对象成为可能,除了可以通过FileSystemObject对象访问文件系统外,也允许进行其他的一些操作,例如处理WSH和ActiveX对象、设定和去除打印机和远程驱动器、操控注册表、创建Windows和Internet的快捷方式、以及访问Windows NT Active Directory服务。
WSH对象模型由下列三种主要对象组成:WScript、WshShell和WshNetwork。
运行其他应用程序
这里提供了从Excel中启动外部应用程序的一种方法。例如,下面的程序启动记事本:

Sub RunNotepad()
    Dim WshShell As Object
    Set WshShell = CreateObject("WScript.Shell")
    WshShell.Run "Notepad"
    Set WshShell = Nothing
End Sub

将相关语句修改为下列语句,分别可以用来启动计算器或浏览器:

WshShell.Run "Calc"
WshShell.Run "Explorer"

可以打开带有指定文档的应用程序而不是打开一个空的应用程序窗口,例如:

Sub OpenTxtFileInNotepad()
    Dim WshShell As Object
    Set WshShell = CreateObject("WScript.Shell")
    WshShell.Run "Notepad C:\Phones.txt"
    Set WshShell = Nothing
End Sub

下面的过程打开MS-DOS窗口并打印当前目录下的文件列表:

Sub RunDOSCommand()
    Dim WshShell As Object
    Set WshShell = CreateObject("WScript.Shell")
    WshShell.Run ("Command /c Dir >1pt1:")
End Sub

创建快捷方式
可以使用Shell对象创建应用程序或者网页的快捷方式。WshShell对象有一个CreateShortcut方法,返回快捷方式对象:

Set myShortcut=WshShell.CreateShortcut(Pathname)

其中,参数Pathname是指定快捷文件完整路径的字符串。所有快捷方式文件都带有扩展名.Ink,并且该扩展名必须包括在文件路径名中。
ShortCut对象的属性和方法介绍如下:
(1)TargetPath属性
代表可执行文件的路径。例如:

WshShell.TargetPath=ActiveWorkbook.FullName

(2)WindowStyle属性
指定快捷方式使用的窗口类型。其中1代表普通窗口,3代表最大化窗口,7代表最小化窗口。例如,

WshShell.WindowStyle=1

(3)HotKey属性
指定键盘快捷方式(例如Alt+f、Shift+g、Ctrl+Shift+z,等等),例如,

WshShell.HotKey="Ctrl+Alt+W"

(4)IconLocation属性
指定快捷方式图标的位置。因为图标文件中通常不止一个图标,所以应该提供图标文件的路径,并且后面标明图标在文件里的索引号。如果不指定,则Windows使用缺省的图标,例如

WshShell.IconLocation="notepad.exe,0"

(5)Description属性
包含一个描述快捷方式的字符串。例如,

WshShell.Description="Wordware Web Site"

(6)WorkingDirectory属性
指定快捷方式的工作目录。例如:

strWorkDir=WshShell.SpecialFolders("Desktop")
WshShell.WorkingDirectory=strWorkDir

(7)Save方法
这是ShortCut对象的唯一方法。在使用CreateShortcut方法创建快捷方式对象并且设置该快捷方式的属性后,必须使用Save方法将快捷方式保存到磁盘上。
下面的过程创建WshShell对象并使用CreateShortcut方法创建两个快捷方式:一个为当前工作簿的快捷方式,另一个为到Wordware Publishing页面的快捷方式。这两个快捷方式均放置在用户桌面上。

Sub CreateShortcut()
    '在桌面创建两个快捷方式
    Dim WshShell As Object
    Dim objShortcut As Object
    Set WshShell = CreateObject("WScript.Shell")
    '创建一个Internet快捷方式
    Set objShortcut = _
 WshShell.CreateShortcut(WshShell.SpecialFolders("Desktop") _
& "\Wordware.url")
    objShortcut.TargetPath = "http://www.wordware.com"
    objShortcut.Save
    '创建一个文件快捷方式
    Set objShortcut = _
 WshShell.CreateShortcut(WshShell.SpecialFolders("Desktop") & _
           "\" & ActiveWorkbook.Name & ".lnk")
 
    With objShortcut
        .TargetPath = ActiveWorkbook.FullName
        .WindowStyle = 7
        .Save
    End With
    Set objShortcut = Nothing
    Set WshShell = Nothing
End Sub

CreateShortcut过程使用WshShell对象的SpecialFolders属性返回Windows桌面的路径。
提示 可以使用SpecialFolders属性查找计算机中特殊文件夹的位置。例如下列特殊文件夹:AllUsersDesktop(所有用户桌面)、AllUsersStartMenu(所有用户开始菜单)、AllUsersPrograms(所有用户程序)、AllUsersStartup(所有用户启动)、Desktop(桌面)、Favorites(收藏夹)、Fonts(字体)、MyDocuments(我的文档)、NetHood(网络连接)、PrintHood(打印机连接)、Programs(程序)、Recent(最近)、SendTo(发送到)、StartMenu(开始菜单)、Startup(启动)和Templates(模板)。如果请求的特殊文件夹不可用,则SpecialFolders属性返回一个空字符串。

相关文章

Page 1 of 3123