VBA: 通过Dir函数查找指定文件

2022-09-20 14:46:57 浏览数 (1)

文章背景: 通过VBA编写代码时,有时需要判断某个文件是否存在;或者判断在文件夹内是否存在指定类型的文件。此时,就会涉及到Dir函数。下面就来介绍Dir函数的语法和应用场景。

1 Dir函数的语法

2 应用示例

2.1 获取指定路径文件的名称

2.2 判断指定路径的文件夹是否存在(不存在则创建它)

2.3 获取指定路径文件夹内所有文件和子文件夹的名称

2.4 获取指定路径文件夹内的所有文件名称

2.5 获取指定路径文件夹内所有子文件夹的名称

2.6 获取指定路径文件夹内第一个txt文件的名称

2.7 获取指定路径文件夹内所有txt文件的名称

1 Dir函数的语法

Dir [ (pathname [ ,attributes ] ) ]

返回一个字符串,该字符串表示与指定模式或文件属性或驱动器卷标匹配的文件、目录或文件夹的名称。

  • pathname 可选参数。用来指定文件名的字符串表达式,可能包含目录或文件夹、以及驱动器。如果没有找到 pathname,则会返回零长度字符串 ("")。
  • attributes 可选参数。常数或数值表达式,其总和用来指定文件属性。如果省略,则会返回匹配 pathname 但不包含属性的文件。

attributes参数可以选择以下值或者以下值的和。

(1)文件和文件夹具有类似只读隐藏系统档案的特点。这些特点就是属性。可以使用GetAttr函数来获得文件或文件夹的属性,具体用法参见文末的参考资料[9]。

(2)当attributes参数不指定时,表示返回没有任何属性的文件。

(3)当pathname参数指定的文件或文件夹找不到时,Dir函数返回一个0长度的空字符串""。

(4)Dir支持使用多字符 ( * ) 和单字符 ( ? ) 通配符来指定多个文件。星号(* )匹配任意个字符(包括0个);问号(?)匹配单个字符。

Wildcard characters can only be used in the last path component of the pathname argument.

例如,你可以使用:

代码语言:javascript复制
filename = Dir("c:ab*")

但你不能使用:

代码语言:javascript复制
filename = Dir("c:mydocuments**")

否则,代码会报错:Run-time error '52': Bad file name or number。

2 应用示例

假如C盘中有如下的文件结构:

代码语言:javascript复制
#   a ->  b  ->  1dog.txt, 2cat.txt
#          c  ->  3panda.txt
#          d  ->  e
#          4duck.txt
#          5horse.txt
2.1 获取指定路径文件的名称

当文件的路径已知,可以通过Dir函数获取文件名称。

代码语言:javascript复制
Sub GetFileNames()

    Dim FileName As String
    
    FileName = Dir("C:ac3panda.txt")
    
    Debug.Print FileName
    
End Sub

运行后,在立即窗口(Immediate Window)中显示的是:

代码语言:javascript复制
3panda.txt

如果指定路径的文件不存在,则Dir函数返回空字符串。以下是改进后的代码。

代码语言:javascript复制
Sub CheckFileExistence()

    Dim FileName As String
    
    FileName = Dir("C:ac3panda.txt")

    If FileName <> "" Then
    
        Debug.Print FileName
        
    Else
    
        Debug.Print "File Doesn't Exist"
        
    End If

End Sub
2.2 判断指定路径的文件夹是否存在(不存在则创建它)
代码语言:javascript复制
Sub CheckDirectory()

    Dim PathName As String
    Dim CheckDir As String

    PathName = "C:ab"
    CheckDir = Dir(PathName, vbDirectory)

    If CheckDir <> "" Then
    
        Debug.Print CheckDir & " exists"
        
    Else
        
        Debug.Print "The directory doesn't exist"
        
    End If

End Sub

运行后,立即窗口中显示的是:

代码语言:javascript复制
b exists

如果指定路径的文件夹不存在,则可以通过MkDir函数来创建它。

代码语言:javascript复制
Sub CreateDirectory()

    Dim PathName As String
    Dim CheckDir As String

    PathName = "C:af"
    CheckDir = Dir(PathName, vbDirectory)

    If CheckDir <> "" Then
    
        Debug.Print CheckDir & " folder exists"
        
    Else
    
        MkDir PathName
        
        CheckDir = Dir(PathName, vbDirectory)
        Debug.Print "A folder has been created with the name " & CheckDir
        
    End If

End Sub

由于文件夹f一开始不存在,因此,运行代码后,会先创建文件夹f,然后在立即窗口中显示:

代码语言:javascript复制
A folder has been created with the name f
2.3 获取指定路径文件夹内所有文件和子文件夹的名称
代码语言:javascript复制
Sub GetAllFileAndFolderNames()

    Dim FileName As String
    
    FileName = Dir("C:a", vbDirectory)

    Do While FileName <> ""
    
        Debug.Print FileName
        
        FileName = Dir()
        
    Loop
    
End Sub

运行后,立即窗口中显示的是:

代码语言:javascript复制
.
..
4duck.txt
5horse.txt
b
c
d
f

(1)返回的名称中包括...两个特殊名字。其中一个点代表的是当前目录,即:C:a;两个点代表的是上级目录,即:C:

(2)Dir函数只能返回第一层的子文件夹和文件名,子文件夹下的文件和文件夹不返回。

2.4 获取指定路径文件夹内的所有文件名称
代码语言:javascript复制
Sub GetAllFileNames()

    Dim FileName As String
    
    FileName = Dir("C:a", vbNormal)

    Do While FileName <> ""
    
        Debug.Print FileName
        
        FileName = Dir()
        
    Loop
    
End Sub

运行后,立即窗口中显示的是:

代码语言:javascript复制
4duck.txt
5horse.txt

(1)attributes参数设置为vbNormal,返回的是无属性文件的名称;

(2)attributes参数设置为vbDirectory,返回的是无属性文件和文件夹的名称。

2.5 获取指定路径文件夹内所有子文件夹的名称

借助GetAttr函数,我们可以判断通过Dir函数返回的名称是属于文件还是文件夹

GetAttr(pathname)

The value returned by GetAttr is the sum of the following attribute values:

代码语言:javascript复制
Sub GetSubFolderNames()

    Dim FileName As String
    Dim PathName As String

    PathName = "C:a"
    FileName = Dir(PathName, vbDirectory)

    Do While FileName <> ""
    
        If (GetAttr(PathName & FileName) And vbDirectory) = vbDirectory Then
        
            Debug.Print FileName
            
        End If
        
        FileName = Dir()
        
    Loop
    
End Sub

运行后,立即窗口中显示的是:

代码语言:javascript复制
.
..
b
c
d
f

(1) 在判断文件是否具有vbDirectory的属性时,这里用到了and运算符。主要考虑到的是GetAttr函数返回的是文件属性之和。比如针对两个点代表的上级目录,即:C:GetAttr("C:")返回的值是22,即16 4 2,因此,它也具有vbDirectory的属性(16)。

如果直接使用GetAttr(PathName & FileName) = vbDirectory,容易把属性值22(16 4 2)或18(16 2)的文件夹漏掉。

(2)对于expression1 And expression2,如果expression1和expression2都是数值表达式,那么And会对表达式相同位置的位进行按位比较。换句话说,先把两个数字转成二进制之后,进行按位比较,然后在转回十进制。

例如,22(10110) and 16(10000),按位比较后,结果是10000,所以22 and 16,得到的是16。

2.6 获取指定路径文件夹内第一个txt文件的名称
代码语言:javascript复制
Sub GetFirstTxtFileName()

    Dim FileName As String
    Dim PathName As String

    PathName = "C:a"
    
    FileName = Dir(PathName & "*.txt")
    
    Debug.Print FileName
    
End Sub

运行后,立即窗口中显示的是:

代码语言:javascript复制
4duck.txt
2.7 获取指定路径文件夹内所有txt文件的名称
代码语言:javascript复制
Sub GetAllTxtFileNames()

    Dim FolderName As String
    Dim FileName As String
    
    FolderName = "C:a"
    
    FileName = Dir(FolderName & "*.txt")

    Do While FileName <> ""
    
        Debug.Print FileName
        
        FileName = Dir()
        
    Loop

End Sub

运行后,立即窗口中显示的是:

代码语言:javascript复制
4duck.txt
5horse.txt

借助通配符,以及Do...Loop循环,我们可以遍历文件夹,找到文件夹内所有满足指定格式的文件名称。当然,Dir函数只能返回第一层的文件,无法返回子文件夹内的文件。

If you want to get the names of all the files in the main folder and the sub-folders, you can’t use the DIR function (as it’s not recursive). To do this, you can either use Power Query (no coding needed) or use the File System Object in VBA (with recursion).

参考资料:

[1] VBA DIR Function – An Easy Explanation with Examples(https://trumpexcel.com/vba-dir-function/)

[2] 目录函数(https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/dir-function)

[3] 用dir 查找文件夹,特定文件名,文件类型,遍历等(https://blog.csdn.net/xuemanqianshan/article/details/103380178)

[4] 文件属性(https://baike.baidu.com/item/文件属性/8830991)

[5] 如何在vba中用dir函数遍历文件夹和文件(http://www.exceloffice.net/archives/966)

[6] VBA中返回和设置文件属性(https://www.w3cschool.cn/excelvba/excelvba-attribute.html)

[7] CopyFolder method(https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/copyfolder-method)

[8] VBA编程知识点(10)——Dir函数(https://zhuanlan.zhihu.com/p/74298565)

[9] GetAttr function(https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/getattr-function)

[10] GetAttr(mypath & myname) And vbDirectory = vbDirectory如何理解(https://club.excelhome.net/thread-1431317-1-1.html)

[11] vba快速入门06-运算符(https://inuwashi123.github.io/post/vba/vba快速入门06-运算符/)

0 人点赞