分享

使用VBA操作文件(2):处理文件的VBA函数和语句

 JT_man 2014-09-16

下面主要介绍专门用于处理文件和文件夹的VBA函数。
CurDir函数
CurDir函数用于获取当前文件夹的路径名称,其语法为:

CurDir([drive])

其中,参数drive可选,若省略该参数,则表示当前驱动器。CurDir函数返回值代表文件路径,Variant型;若要返回字符串型的文件路径,则使用CurDir$函数。
例如,如果工作簿保存在C盘,则下面的指令:

Left(CurDir$,1)

返回值为:C。
Name函数
Name函数用于更改文件或者文件夹的名称,其语法为:

Name old_pathname As new_pathname

其中,参数old_pathname代表希望重命名的文件或文件夹的路径和名称,而参数new_pathname用于指定文件或文件夹的位置和新名称。使用Name函数,可以将文件从一个文件夹移至另一个文件夹,但是该函数不能移动文件夹。
在使用Name函数时,应该注意以下几点:

  • 参数old_pathname所指定的文件必须存在,否则会发生错误:文件未找到。
  • 参数new_pathname所指定的文件名称不能与文件夹中已经存在的文件名称相同。例如,在C盘中已经存在文件名testNewFile.txt,下面的语句:
    Name "C:\testOldFile.txt" As "C:\testNewFile.txt"

    将出现错误:文件已存在。

  • 如果参数new_pathname所指定的文件名称与参数old_pathname所指定的文件名称不同,则在移动文件的同时将该文件名称更改为参数new_pathname所指定的新名称。例如:
    Name "C:\testOldFile.txt" As "D:\testNewFile.txt"

    将文件testOldFile.txt移至D盘并将其名称更改为testNewFile.txt。

  • 如果参数new_pathname和参数old_pathname所指定的文件路径不同但文件名称相同,则Name函数将指定的文件移动到参数new_pathname指定的文件路径下并保持文件名称不变。
  • 不能够更改已打开的文件的名称。
  • 在更改文件名称时,文件名称中不能包含通配符“*”或者“?”。
  • 在更改文件名称时,new_pathname和old_pathname不能是在不同的驱动器上。
  • Name语句可以将文件从一个文件夹移到另一个文件夹中,同时也可以改变文件的名字。如果new_pathname中指定的文件夹存在而且和old_pathname中给出的不同,文件就会被移到new_pathname指定的文件夹中。如果new_pathname和old_pathname中的文件名也不同,这个文件就会被改名。但是,以这种方式移动对象只对文件有效,不能使用Name语句来移动文件夹。

Dir函数
Dir函数返回文件或者文件夹的名称,常用来检查磁盘中是否存在指定的文件或文件夹,如果不存在,那么返回空字符串(””)。Dir函数的语法如下:

Dir[(pathname[,attributes])]

其中,参数pathname为可选参数,是代表文件或文件夹的名称的字符串,包括驱动器名称。参数attributes可以使用下面列出的任一常量或者数值,指定文件的属性:

常量 属性含义
vbNormal 0 普通文件
vbHidden 2 隐藏文件
vbSystem 4 系统文件
vbVolume 8 卷标。若指定了该属性,则会忽略其他所有属性
vbDirectory 16 目录或文件夹


attributes常量能够组合在一起产生相应的组合属性进行匹配,例如vbHidden+vbDirectory组合表示隐藏目录。对象浏览器和VBA列表中还给出了其他几个常量(如vbReadOnly、vbArchive),它们能作为attributes参数的值,但却不能在Windows平台上使用,也不能影响函数的操作。
尽管参数pathname为可选参数,但在第一次调用Dir函数时必须包含参数pathname。而且如要指定了参数attributes,则同时必须指定参数pathname。此外,一旦Dir函数返回一个零长字符串,以后再次调用Dir函数之前必须指定参数pathname,否则将产生错误“无效的过程调用或参数”。
Dir函数返回字符串子类型的变体,而Dir$函数返回字符串数据类型。如果没有发现与传递给函数的模式或文件属性相匹配的文件,则返回零长字符串(””)。
例如,下面的指令:

Dir("C:\",vbNormal)

返回指定文件夹中第一个文件的名称。常量参数vbNormal指除隐藏、卷标、目录、文件夹或系统文件之外的任何文件。
Dir函数允许在指定的文件路径名称中使用通配符返回多个文件,其中星号(*)代表多个字符,问号(?)代表单个字符。例如,下面的过程列出指定目录下文件的名称。

Sub ListFiles()
    Dim strFile As String
    Dim strPath As String
 
    strPath = InputBox("请输入路径名称,例如C:\MyDirectory")
    If Right(strPath, 1) <> "\" Then strPath = strPath & "\"
 
    strFile = Dir(strPath & "*.*")
    If strFile <> "" Then Debug.Print "在文件夹" & strPath & "中的文件有:"
    Debug.Print LCase$(strFile)
    If strFile = "" Then
        MsgBox "没有找到文件."
        Exit Sub
    End If
    Do While strFile <> ""
        strFile = Dir
        Debug.Print LCase$(strFile)
    Loop
End Sub

ListFiles过程首先询问用户输入文件路径名称,如果输入的路径末尾没有反斜杠,则在其后添加反斜杠。接着,在指定的文件路径中搜索所有文件(*)。如果该文件夹中没有文件,则显示提示信息;如果存在文件,则将所有文件名显示在立即窗口中。
下面的过程获取C盘根目录下的所有文件名称并将其写入工作表Sheet1中:

Sub GetFiles()
    Dim strFile As String
    Dim iRow As Integer
    iRow = 1
    With Worksheets("Sheet1").Range("A1")
        strFile = Dir("C:\", vbNormal)
        .Value = strFile
        Do While strFile <> ""
            strFile = Dir
            .Offset(iRow, 0).Value = strFile
            iRow = iRow + 1
        Loop
    End With
End Sub

示例:在列表框中列出指定目录中指定类型的所有文件

Private Sub CommandButton1_Click()
    Dim sFilename As String
    Dim sPath As String
 
    sPath = "C:\Windows\*.txt"
    sFilename = Dir$(sPath)
 
    Do While sFilename <> ""
        ListBox1.AddItem sFilename
        sFilename = Dir$
    Loop
End Sub

Dir函数一次只能返回一个文件名。如果要获得多个与参数pathname相匹配的文件,那么第一次调用Dir函数时必须使用必要的参数,而在以后调用Dir函数时则不再使用参数。如果没有一个文件名与初始的设置相匹配,那么函数将返回一个零长字符串。一旦Dir函数返回一个零长字符串,以后再次调用Dir函数时就必须指定参数pathname,否则将产生错误。上面的示例在用户窗体中使用一个命令按钮和一个列表框控件,说明如何在VBA应用程序中使用Dir函数。
Dir函数是惟一不需要创建错误处理程序而能够判断文件是否存在的方法。使用Dir函数判断文件是否存在很简单,只需要将测试文件名传递给该函数即可。如果Dir函数返回一个零长字符串,则表明文件不存在,如下面的代码:
示例:判断文件是否存在

Public Function FileExists(sPath As String) As Boolean
    If Dir(sPath) <> "" Then
        FileExists = True
    Else
        FileExists = False
    End If
End Function

Dir函数返回的文件名在文件地址分配表中按顺序显示。如果需要以特定的顺序显示文件名,则必须在排序前先把文件名存储在一个数组中,然后再按需要的顺序排列。
Dir函数保存它在调用之前的状态,这意味着不能递归调用Dir函数。例如,如果Dir函数返回一个目录的名称,那么就不能调用Dir函数迭代该目录下的文件并返回到原来的目录。
如果将参数attributes只设置为vbDirectory,则该函数的作用将与原来有所不同。如果参数pathname使用了通配符,则该函数仅仅返回与搜索条件相匹配的第一个目录。如果不提供新的参数pathname而连续调用Dir函数,则按文件的顺序返回文件名。
如果调用Dir函数返回的文件名不止一个,则必须提供一个显式的文件规范。即如果希望获得Windows目录下所有文件的名称,不能使用下面的语句:

strFile=Dir("C:\Windows",vbNormal)

而应该使用如下列语句指定的参数pathname来调用Dir函数:

strFile=Dir("C:\Windows\*.*",vbNormal)

Dir函数和Dir$函数仅仅返回文件名称,而不提供文件大小、日期和数据、时间戳或者文件属性等信息。此时,利用File System对象模型中的File对象的Attributes属性很容易获得这些信息。
使用Dir函数的一个关键在于要清楚各种属性常量如何影响文件或者Dir函数如何返回文件。在默认情况下,Dir函数返回一个普通文件(即属性没有设置为隐藏或者系统的文件)。vbHidden属性返回隐藏文件或者常规文件,而不是返回系统文件或者隐藏的系统文件。vbSystem属性返回系统文件或常规文件,而不是返回隐藏文件或隐藏的系统文件。vbSystem+vbHidden属性则返回任何文件,无论是常规文件、隐藏文件还是系统文件。
FileAttr函数
确定一个用Open语句打开的文件的访问模式。如果在16位的Windows系统中使用,则FileAttr函数可以获得一个操作系统文件句柄。其语法为:

FileAttr (filenumber,[returntype])

其中,参数filenumber必需,为任何有效的文件号,Integer类型。参数returntype必需,指定返回信息的可选的数字,Integer类型,如果忽略该参数则缺省值为1。
如果将参数returntype指定为1,则把文件访问模式作为长整型数返回,如下表格所示。

模式
输入 1
输出 2
随机 4
追加 8
二进制 32


将参数returntype设置为1可以获得一个表示文件打开模式的返回值。将参数returntype设置为2可以获得操作系统的文件句柄(仅适用于16位Windows系统)。
交叉参考:File System对象模型中包含File对象,该对象有一个Attributes属性及其它属性,能够获得比FileAttr函数更多的信息。
FileDateTime函数
FileDateTime函数用来检查某文件最后修改的日期和时间,其语法为:

FileDateTime(Pathname)

其中,参数Pathname为一个字符串,指定希望处理的文件,可以包括驱动器和文件夹名称。该函数返回某文件修改时的日期和时间,日期和时间的格式取决于Windows控制面板的区域设置。
提示:如果需要单独返回日期和时间,那么可以将FileDateTime函数作为DateValue函数或TimeValue函数的参数来使用。
调用FileDateTime函数之前,应该用Dir函数确定文件是否存在。如果文件不存在,则应用程序产生运行时错误“找不到文件”。
FileDateTime函数是一个只读函数,只能够读取数据而不能设置文件的日期和时间属性。
如果创建文件后已经修改了文件,FileDateTime函数只返回最近一次修改的日期。要获得文件的创建日期,必须使用Windows API。GetFileTime API调用不仅能返回文件最近一次修改的日期,而且能返回文件的创建日期和最近一次访问的日期。
对隐藏文件也能使用FileDateTime函数。
交叉参考:File System对象允许使用File对象引用一个文件,可以用它获得文件的创建日期、最近一次访问和修改的日期。
FileLen函数
FileLen函数用来获取文件的大小,因此可使用该函数检查某文件是否能够保存在某磁盘上,即该磁盘的容量能否容纳该文件。其语法为:

FileLen(Pathname)

其中,参数Pathname为一个字符串,指定希望处理的文件,可以包括驱动器和文件夹的名称。该函数以字节形式返回文件的大小,如果该文件已打开,则返回其最后一次保存时的大小。
因为FileLen函数是根据文件分配表返回文件长度的,所以FileLen函数的返回值反映了文件打开前的大小。对于已经打开的文件,应该使用LOF函数来确定该文件的当前长度。
GetAttr函数和SetAttr函数
GetAttr函数用来获得文件或文件夹的属性,其语法为:

GetAttr(Pathname)

其中,参数Pathname指定希望处理的文件或文件夹的路径名称。该函数返回一个整数,代表下面的表格显示的常量中的一个或多个常量之和。

常量 属性含义
vbNormal 0 普通文件(没有设置其他属性)
vbReadOnly 1 不可修改的文件或文件夹
vbHidden 2 在普通设置下不可见的文件或文件夹
vbSystem 4 系统文件
vbDirectory 16 目录
vbArchive 32 档案(在最后一次备份后,该文件已被修改)


提示:文件和文件夹具有诸如“只读”、“隐藏”、“系统”、“档案”等特点,这些特点称为属性。
如果希望知道某文件是否具有特定的属性,那么可以使用AND运算符将GetAttr函数的结果与常量值相比较。如果返回一个非零数值,则表明具有该特定的属性。例如:

GetAttr("C:\MsDos.sys") AND vbReadOnly

SetAttr函数用来设置文件或文件夹的属性,其语法为:

SetAttr Pathname,Attributes

其中,参数Pathname为一个字符串,代表希望处理的文件或文件夹;参数Attributes是一个或多个希望设置的属性常量,参见上面的表格。
提示:不能给打开的文件设置属性,如果希望使用SetAttr函数给打开的文件设置属性,则必须先关闭该文件。
ChDir语句和ChDrive语句
使用ChDir语句来更改默认的文件夹,其语法为:

ChDir Path

其中,Path是指定新的默认文件夹名称的字符串,可以包含驱动器名。如果在Path中没有包括驱动器名,那么默认文件将会更改为当前驱动器。注意,此时默认文件夹改变并不会改变当前的默认驱动器。例如,如果当前驱动器为C:\,使用下列语句:

ChDir "D:\MyFolder"

将驱动器D:中的当前文件夹改为“D:\MyFolder”,但当前驱动器仍然是C:\。
如果没有找到参数Path指定的路径,则会导致错误“找不到路径”;如果参数Path指向网络上的另一台计算机,则会导致错误“路径/文件访问错误”。
要更改当前默认的驱动器,则使用ChDrive语句,其语法为:

ChDrive Drive

其中,Drive是指定新的默认驱动器的字符串,用来设置默认驱动器的名称(A~Z)。如果指向一个并不存在的驱动器,则会出现信息框“设备不可用”;如果Drive指定为零长的字符串,则不会改变驱动器;如果Drive包含不止一个字符,则只有第一个字符代表用来设置的驱动器。
示例:下面的函数IsAvailableDrive用来确定指定的驱动器是否可用。

Private Function IsAvailableDrive(sDrive As String) As Boolean
    On Error Resume Next
    Dim sCurDrv As String
    '获取代表当前驱动器的字母
    sCurDrv = Left$(CurDir$, 1)
    '试着改变驱动器
    ChDrive sDrive
    '根据是否有错误发生判断驱动器是否可用
    If Err.Number = 0 Then
        '没有发生错误-该驱动器可用
        IsAvailableDrive = True
    Else
        '有错误发生-该驱动器不可用
        IsAvailableDrive = False
    End If
    '恢复驱动器默认设置
    ChDrive sCurDrv
End Function

使用下面的测试程序来测试该函数:

Sub test()
    Dim sDrv As String
    sDrv = "T" '改为您要判断的驱动器字母或者改为由用户输入
    If IsAvailableDrive(sDrv) Then
        ChDrive sDrv
    Else
        MsgBox "不能够使用驱动器" & sDrv & ":\"
    End If
End Sub

该函数是一个通用函数,在需要使用ChDrive的情形时,能够减少代码的数量。
MkDir语句和RmDir语句
使用MkDir语句可以创建一个新文件夹,其语法为:

MkDir Path

其中,Path指定希望创建的新文件夹名称,若省略驱动器名称,则在当前驱动器上创建新文件夹。
在调用MkDir语句之后,VB并不自动把新建文件夹视作当前文件夹,如果要这样,必须使用ChDir语句。
使用RmDir语句删除不需要的文件夹,其语法为:

RmDir Path

其中,Path指定希望删除的文件夹的名称,若省略驱动器名称,则删除当前驱动器中存在的相同名称的文件夹。若指定的文件夹不存在,则会出现错误信息“路径未找到”。
提示:RmDir语句只能删除空文件夹,也就是说,如果文件夹中包含有文件,那么使用RmDir语句删除文件夹时会导致错误。此时,应该先使用Kill语句删除文件夹中的文件,再使用RmDir删除该文件夹。
使用Kill语句和ReDim语句的删除是不可逆的,因为这些语句不会把删除掉的文件放到回收站中。
为了删除文件夹,可以递归调用Dir函数引导到文件夹中的子文件夹。要注意的是,该函数可以每次在调用之前保存状态信息。
下面的过程删除一个文件夹中的所有文件并移动它的子文件夹,如果那些文件夹中还包含文件或文件夹,则可以通过递归调用该过程来删除它们,直到把所有的子文件夹以及它们的文件都删除为止。

Private Sub RemoveFolder(ByVal strFolder As String)
    Static blnLowerLevel As Boolean '递归调用-不需要提示用户
    Dim blnRepeated As Boolean '在重复调用中使用Dir状态信息
    Dim strFile As String '在strFolder中包含文件/目录
    '删除所有文件
    Do
        strFile = Dir(strFolder & "\*.*", vbNormal Or vbHidden Or vbSystem)
        If strFile <> "" Then
            If Not blnLowerLevel Then
                If MsgBox("Delete files in directory " & _
                        strFolder & "?", _
                        vbQuestion Or vbOKCancel, _
                        "Confirm File Deletion") _
                        = vbCancel Then Exit Sub
            End If
            strFile = strFolder & "\" & strFile
            Kill strFile
        End If
    Loop While strFile <> ""
    '删除所有目录
    Do
        If Not blnRepeated Then
            strFile = Dir(strFolder & "\*.*", vbDirectory)
            blnRepeated = True
        Else
            strFile = Dir(, vbDirectory)
        End If
        If strFile <> "" And strFile <> "." And strFile <> ".." Then
            If Not blnLowerLevel Then
                blnLowerLevel = True
                If MsgBox("Delete subdirectories of " & _
                           strFolder & "?", _
                           vbQuestion Or vbOKCancel, _
                           "Confirm Directory Deletion") _
                           = vbCancel Then Exit Sub
            End If
            RemoveFolder strFolder & "\" & strFile
            blnRepeated = False
        End If
    Loop While strFile <> ""
    RmDir strFolder
End Sub

交叉参考:VB6中新的File System对象模型包含Folders集合对象和Folder对象,它们比内置的文件夹管理函数更加灵活、方便。
FileCopy语句
FileCopy语句用于在文件夹之间复制文件,其语法为:

FileCopy source,destination

两个参数都是必需的参数。其中,第一个参数source指定要复制的文件名称,可以包含驱动器名称,String类型。第二个参数destination指定复制到的地点,同样可以包含驱动器和文件夹的名称,String类型。不能复制当前已经打开的文件。
如果没有在参数source和参数destination中指定驱动器或文件夹,则认为文件在当前的驱动器或文件夹中。在使用FileCopy语句时,只输入一个destination路径是不够的,必须提供一个文件名,即使它与source的内容相同也可以,否则会产生运行时错误“路径/文件访问错误”。
FileCopy是一个语句而不是函数,没有返回值。因此可假定如果调用FileCopy语句时没有错误生成,就认为成功复制了文件。所以应该为FileCopy语句编写良好的错误处理程序。注意,如果destination指定的文件已经存在,就会直接覆盖该文件而不会预先提示用户。
交叉参考:File System对象有几种可以用于复制、移动文件和文件夹的方法。
下面的代码将用户指定的文件复制到名为“C:\MyDir”的文件夹中:

Sub CopyToMyDir()
    Dim strFolder As String
    Dim strSource As String
    Dim strDestination As String
    Dim strMsg1 As String
    Dim strMsg2 As String
    Dim iP As Integer
    Dim iSS As Integer
    Dim i As Long
 
    On Error GoTo ErrorHandler
 
    strFolder = "C:\MyDir"
    strMsg1 = "该文件已存在于文件夹中."
    strMsg2 = "复制到"
    iP = 1
    i = 1
 
    '获取文件名
    strSource = Application.GetOpenFilename
    '如果单击取消则不做任何操作
    If strSource = "False" Then Exit Sub
    '获取变量strSource中的反斜杠总数
    Do Until iP = 0
        iP = InStr(i, strSource, "\", 1)
        If iP = 0 Then Exit Do
        iSS = iP
        i = iP + 1
    Loop
    '创建目标文件名
    strDestination = strFolder & Mid(strSource, iSS, Len(strSource))
    '使用该名称创建新文件夹
    MkDir strFolder
    '检查指定的文件是否已存在于目标文件夹中
    If Dir(strDestination) <> "" Then
        MsgBox strMsg1
    Else
        '复制所选文件到C:\MyDir文件夹中
        FileCopy strSource, strDestination
        MsgBox strSource & " " & strMsg2 & " " & strDestination
    End If
    Exit Sub
ErrorHandler:
    If Err = "75" Then
        Resume Next
    End If
    If Err = "70" Then
        MsgBox "不可以复制已经打开的文件."
    End If
End Sub

CopyToMyDir过程使用GetOpenFilename方法从用户处获取文件名称,此时将出现内置的“打开”对话框,从中选择文件,如果用户单击“取消”按钮,则返回值“False”,从而结束程序;如果用户单击“打开”按钮,则选中的文件的完整路径和名称就被赋值给变量strSource。因为仅需要文件名称,所以使用Do Until循环找到最后一个反斜杠在变量strSource中的位置。接着,为FileCopy语句的第二个参数准备字符串,并将其值赋给变量strDestination,该变量存储的字符串为目标文件夹加反斜杠加用户指定的文件名。如果目标文件夹不存在,则使用MkDir函数创建新文件夹。然后,程序检查所选择的文件是否已经存在于目标文件夹中,如果文件已存在,则为用户给出提示信息;如果文件不存在且该文件没有被打开则将该文件复制到指定的文件夹并显示相应的信息。如果文件被打开,则会出现错误从而显示相应的提示。
Kill语句
Kill语句可以删除文件夹中的文件,其语法为:

Kill Pathname

其中,Pathname指定希望删除的一个或多个文件的名称,可以包括驱动器和文件夹名称,可以使用通配符(*或?)来快速删除文件,但不能删除已经打开的文件或者被设置成只读属性的文件。
下面的程序代码删除上一节中C:\MyDir文件夹中的文件,最后删除该文件夹自身:

Sub RemoveFolder()
    Dim strFolder As String
    Dim strFile As String
 
    '将文件夹名称赋值给变量,注意加上末尾处的反斜杠
    strFolder = "C:\MyDir\"
    strFile = Dir(strFolder, vbNormal)
    Do While strFile <> ""
        Kill strFolder & strFile
        strFile = Dir
    Loop
    RmDir strFolder
End Sub

在Windows 95和NT环境下,删除的文件并不放在回收站里面,但是下面的代码段说明如何利用Shell32.DLL中的FileOperation API函数将文件移到Windows 95或NT4的回收站中。

'声明文件操作结构
Type SHFILEOPSTRUCT
    hWnd As Long
    wFunction As Long
    pFrom As String
    pTo As String
    fFlags As Integer
    fAborted As Boolean
    hNameMaps As Long
    sProgress As String
End Type
 
'声明删除操作需要的两个常数
Private Const FO_DELETE = &H3
Private Const FO_FLAG_ALLOWUNDO = &H40
 
'声明API调用函数
Declare Function SHFileOperation Lib "shell32.dll" _
          Alias "SHFileOperationA" _
          (lpFileOp As SHFILEOPSTRUCT) As Long
 
Public Function WinDelete(sFileName As String) As Long
    '创建文件操作结构的副本
    Dim SHFileOp As SHFILEOPSTRUCT
    '需要以Null结尾的字符串
    sFileName = sFileName & vbNullChar
    '将相关值赋给结构
    With SHFileOp
        .wFunction = FO_DELETE
        .pFrom = sFileName
        .fFlags = FO_FLAG_ALLOWUNDO
    End With
    '将结构传递给API函数
    WinDelete = SHFileOperation(SHFileOp)
End Function

对于文件夹的删除,应使用RmDir语句。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多