VBA 工作簿与工作表:打开、批量处理、保存、关闭与事件

适用场景

把同一个文件夹里的几十个工作簿合并到一张表、按模板批量生成文件、打开文件时自动刷新、修改单元格时自动记录时间。工作簿和工作表操作的核心是明确对象:操作哪个文件、哪张表,不能依赖“当前激活”的是谁。

常用对象

对象 含义 写法
ThisWorkbook 代码所在的工作簿 ThisWorkbook.Worksheets("汇总")
ActiveWorkbook 当前激活的工作簿 用户可能切换,慎用
Workbooks("报表.xlsx") 按名称取已打开的工作簿 名称要包含扩展名
Workbooks.Open 打开文件 Set wb = Workbooks.Open(path)
Workbooks.Add 新建工作簿 Set wb = Workbooks.Add
Worksheets("Sheet1") 按名称取工作表 不含图表工作表
Sheets(1) 按索引取工作表 包含图表工作表
ThisWorkbook.Path 当前文件所在目录 不含末尾分隔符

打开、保存、关闭

Sub OpenAndClose()
    Dim wb As Workbook
    Dim path As String

    path = ThisWorkbook.Path & Application.PathSeparator & "数据.xlsx"
    Set wb = Workbooks.Open(path, ReadOnly:=True)
    Debug.Print wb.Worksheets(1).Range("A1").Value
    wb.Close SaveChanges:=False
End Sub

保存:

wb.Save
wb.SaveAs Filename:=ThisWorkbook.Path & "\结果.xlsx", FileFormat:=xlOpenXMLWorkbook
wb.SaveAs Filename:=ThisWorkbook.Path & "\结果.xlsm", FileFormat:=xlOpenXMLWorkbookMacroEnabled
wb.SaveCopyAs ThisWorkbook.Path & "\备份.xlsx"

批量处理文件夹

Sub MergeWorkbooks()
    Dim folderPath As String
    Dim fileName As String
    Dim wb As Workbook
    Dim dest As Worksheet
    Dim lastRow As Long

    folderPath = ThisWorkbook.Path & Application.PathSeparator & "数据"
    Set dest = ThisWorkbook.Worksheets("汇总")

    Application.ScreenUpdating = False
    Application.DisplayAlerts = False

    fileName = Dir(folderPath & Application.PathSeparator & "*.xlsx")
    Do While fileName <> ""
        Set wb = Workbooks.Open( _
            folderPath & Application.PathSeparator & fileName, _
            ReadOnly:=True)

        lastRow = dest.Cells(dest.Rows.Count, "A").End(xlUp).Row
        wb.Worksheets(1).Range("A2:D100").Copy _
            Destination:=dest.Range("A" & lastRow + 1)

        wb.Close SaveChanges:=False
        fileName = Dir
    Loop

    Application.DisplayAlerts = True
    Application.ScreenUpdating = True
End Sub

示例里的 A2:D100 是固定范围;实际使用时应先求源表最后一行。Dir 循环第一次传路径,后续不传参数,直到返回空字符串。

工作表操作

Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets.Add(After:=ThisWorkbook.Worksheets(1))
ws.Name = "临时"

ws.Copy After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count)
ws.Visible = xlSheetHidden          ' 隐藏,用户可在菜单取消隐藏
ws.Visible = xlSheetVeryHidden      ' 深度隐藏,只能通过 VBA 恢复
ws.Protect Password:="1234"
ws.Unprotect Password:="1234"

删除工作表:

Application.DisplayAlerts = False
ThisWorkbook.Worksheets("临时").Delete
Application.DisplayAlerts = True

删除前确认表里没有需要保留的数据;删除工作表不能撤销。

事件

事件代码必须写在对应的模块里:

' ThisWorkbook 模块
Private Sub Workbook_Open()
    ThisWorkbook.Worksheets("汇总").Range("A1").Value = Now
End Sub
' Sheet1 模块
Private Sub Worksheet_Change(ByVal Target As Range)
    If Intersect(Target, Me.Range("A:A")) Is Nothing Then Exit Sub

    Application.EnableEvents = False
    On Error GoTo Cleanup
    Target.Offset(0, 1).Value = Now
Cleanup:
    Application.EnableEvents = True
End Sub

修改单元格会再次触发 Change,所以要先关闭事件,处理完再打开;出错时也要恢复,否则后续事件都不再触发。

易错点

相关条目

参考链接

读完自测

合上页面,先回答,再展开对照。

  1. ThisWorkbook 和 ActiveWorkbook 有什么区别?
  2. 为什么事件代码里要临时设置 EnableEvents = False?
  3. SaveAs 和 SaveCopyAs 有什么区别?
答案
  1. ThisWorkbook 是代码所在的工作簿;ActiveWorkbook 是当前激活的工作簿,可能被用户切换。
  2. 修改单元格会再次触发 Change 事件,关闭事件可以避免递归;处理完必须恢复。
  3. SaveAs 改变当前工作簿指向的文件;SaveCopyAs 只复制一份,不改变当前文件。
微信小程序码:扫码打开命令速查小程序

小程序版

微信扫码,随时查命令