乐于分享
好东西不私藏

从0学Excel VBA编程 · 番外总结:全自动日报工具

从0学Excel VBA编程 · 番外总结:全自动日报工具

从0学Excel VBA编程 · 番外总结:全自动日报工具

学习目标

  1. 看清"全自动日报"由哪些零件拼成(合并→汇总→导出→发信→定时→日志)
  2. 拿到一套可复制的完整代码,把番外篇 1~6 的功能串成一条龙
  3. 学会用配置文件记住收件人、用定时框架让报表每天自己跑

知识点精讲

前面 6 个番外篇我们各自学了一块本事:

  • 番外篇1 字典:去重、计数、按列汇总(本篇用它做"按产品汇总销量")
  • 番外篇2 FSO:批量管文件、读写配置文件(本篇用它遍历文件夹 + 读写 config.txt
  • 番外篇3 FSO+Excel 合并:把一文件夹表格合并到"汇总"表
  • 番外篇4 合并后去重/汇总:用字典把"汇总"表按产品汇总成"销量汇总"表
  • 番外篇5 导出/邮件:把结果存成带日期的 xlsx,并用 Outlook 发邮件
  • 番外篇6 定时运行:用 Application.OnTime 让报表每天定时自动跑

收尾篇就是把它们拼成一台"自动日报机":你准备好「待合并」文件夹(每天把各分店 Excel 丢进去),打开本工作簿 → 它按配置自动合并、汇总、导出、发邮件给领导,并把每次运行情况写进"运行记录";配合定时框架,还能每天上班前自己跑完。

五个零件,一条流水线:

待合并文件夹 → ①FSO合并 → 汇总表 → ②字典汇总 → 销量汇总表 → ③导出xlsx → ④Outlook发邮件 → ⑤运行记录                                                                          ↑                                          配置 config.txt(记住收件人/导出路径)贯穿全程                                          定时 OnTime(Workbook_Open安排 / BeforeClose取消)驱动自动跑

3 个实战案例

准备工作(三个案例通用):把本工作簿保存到某文件夹,旁边建一个「待合并」文件夹,里面放若干结构相同的分店 Excel(第 1 列=产品,第 3 列=销量)。所有代码放在「标准模块」;案例 3 另需 ThisWorkbook 模块。

案例 1(简单):手动一键跑完整日报(合并→汇总→导出)

功能说明:点一下按钮,就自动合并「待合并」、按产品汇总、导出成带日期的 xlsx,并把"运行记录"写一笔。不含邮件和定时,先让你看到全链路跑通。

操作步骤

  1. 按 Alt + F11 打开 VBA 编辑器,插入「标准模块」。
  2. 粘贴下面全部代码(含合并、汇总、导出、记录四个过程 + 主过程 一键跑日报)。
  3. 确保有「待合并」文件夹且里面有 Excel,运行"一键跑日报"。
  4. 工作簿里多出生"汇总""销量汇总""运行记录"三张表,目录里多出 销量汇总_日期.xlsx
Sub 一键跑日报()    On Error GoTo 出错    合并待合并文件夹    按产品汇总销量    Dim 路径 As String    路径 = 导出销量汇总    ThisWorkbook.Save    写运行记录 "日报已生成(未发送):" & 路径    MsgBox "日报已生成:" & vbCrLf & 路径, vbInformation    Exit Sub出错:    写运行记录 "出错:" & Err.Description    MsgBox "出错:" & Err.Description, vbCriticalEnd SubSub 合并待合并文件夹()    Dim fso As Object, 文件夹 As Object, 文件 As Object    Dim 源表 As Worksheet, 源簿 As Workbook, 总表 As Worksheet    Dim 源末行 As Long, 列数 As Long, 是首份 As Boolean    On Error Resume Next    Set 总表 = ThisWorkbook.Sheets("汇总")    On Error GoTo 0    If 总表 Is Nothing Then        Set 总表 = ThisWorkbook.Sheets.Add        总表.Name = "汇总"    End If    总表.Cells.Clear    是首份 = True    Set fso = CreateObject("Scripting.FileSystemObject")    Set 文件夹 = fso.GetFolder(ThisWorkbook.Path & "\待合并")    For Each 文件 In 文件夹.Files        If LCase(fso.GetExtensionName(文件.Name)) = "xlsx" Then            Set 源簿 = Workbooks.Open(文件.Path)            Set 源表 = 源簿.Sheets(1)            源末行 = 源表.Cells(源表.Rows.Count, 1).End(xlUp).Row            If 源末行 > 1 Then                If 是首份 Then                    列数 = 源表.UsedRange.Columns.Count                    源表.Range("A1").Resize(源末行, 列数).Copy 总表.Range("A1")                    是首份 = False                Else                    源表.Range("A2").Resize(源末行 - 1, 列数).Copy _                        总表.Cells(总表.Rows.Count, 1).End(xlUp).Offset(1, 0)                End If            End If            源簿.Close False        End If    Next 文件End SubSub 按产品汇总销量()    Dim 总表 As Worksheet, 结果表 As Worksheet    Dim 字典 As Object, 末行 As Long, i As Long    Dim 产品 As String, 销量 As Double, 键 As Variant, r As Long    Set 总表 = ThisWorkbook.Sheets("汇总")    On Error Resume Next    Set 结果表 = ThisWorkbook.Sheets("销量汇总")    On Error GoTo 0    If 结果表 Is Nothing Then        Set 结果表 = ThisWorkbook.Sheets.Add        结果表.Name = "销量汇总"    End If    Set 字典 = CreateObject("Scripting.Dictionary")    末行 = 总表.Cells(总表.Rows.Count, 1).End(xlUp).Row    For i = 2 To 末行        产品 = 总表.Cells(i, 1).Value        If 产品 <> "" Then            销量 = Val(总表.Cells(i, 3).Value)            If 字典.Exists(产品) Then                字典(产品) = 字典(产品) + 销量            Else                字典.Add 产品, 销量            End If        End If    Next i    结果表.Cells.Clear    结果表.Range("A1").Value = "产品"    结果表.Range("B1").Value = "销量合计"    r = 2    For Each 键 In 字典.Keys        结果表.Cells(r, 1).Value = 键        结果表.Cells(r, 2).Value = 字典(键)        r = r + 1    Next 键End SubFunction 导出销量汇总() As String    Dim 源表 As Worksheet, 新簿 As Workbook    Dim 保存路径 As String, 日期戳 As String    日期戳 = Format(Date, "yyyy-mm-dd")    保存路径 = ThisWorkbook.Path & "\销量汇总_" & 日期戳 & ".xlsx"    Set 源表 = ThisWorkbook.Sheets("销量汇总")    Set 新簿 = Workbooks.Add    源表.UsedRange.Copy 新簿.Sheets(1).Range("A1")    新簿.SaveAs 保存路径, 51    新簿.Close False    导出销量汇总 = 保存路径End FunctionSub 写运行记录(内容 As String)    Dim 记录表 As Worksheet, 末行 As Long    On Error Resume Next    Set 记录表 = ThisWorkbook.Sheets("运行记录")    On Error GoTo 0    If 记录表 Is Nothing Then        Set 记录表 = ThisWorkbook.Sheets.Add        记录表.Name = "运行记录"        记录表.Range("A1").Value = "运行时间"        记录表.Range("B1").Value = "说明"    End If    末行 = 记录表.Cells(记录表.Rows.Count, 1).End(xlUp).Row + 1    记录表.Cells(末行, 1).Value = Now    记录表.Cells(末行, 2).Value = 内容End Sub

要点:四个"零件过程"(合并待合并文件夹/按产品汇总销量/导出销量汇总/写运行记录)就是番外篇 3、4、5 的整合版;一键跑日报 按顺序调用它们,并用 On Error GoTo 出错 兜住异常,出错也写进运行记录而不是让程序崩掉。


案例 2(中等):读配置 + 合并 + 汇总 + 导出 + 发邮件(完整手动版)

功能说明:在案例 1 基础上,增加"配置文件"能力——用 config.txt 记住收件人邮箱和导出路径,跑完导出后自动用 Outlook 把文件发给领导(先 .Display 预览确认)。换电脑、换收件人只改配置文件,不动代码。

操作步骤

  1. 在案例 1 代码基础上,再粘贴下面「配置 + 邮件」这一段(含 读配置/初始化配置/发送邮件 和主过程 跑日报并发送)。
  2. 先运行"初始化配置",工作簿目录会生成 config.txt,用记事本打开把 收件人= 改成真实邮箱。
  3. 运行"跑日报并发送":Outlook 弹出邮件预览,确认后点发送即可。
' ===== 配置相关(番外篇2 FSO 读写 config.txt) =====Function 读配置(键 As String) As String    Dim fso As Object, 文件 As Object, 行 As String, 部分() As String    Dim 路径 As String    路径 = ThisWorkbook.Path & "\config.txt"    Set fso = CreateObject("Scripting.FileSystemObject")    If Not fso.FileExists(路径) Then Exit Function    Set 文件 = fso.OpenTextFile(路径, 1)   ' 1 = 读    Do While Not 文件.AtEndOfStream        行 = 文件.ReadLine        If InStr(行, "=") > 0 Then            部分 = Split(行, "=", 2)            If Trim(部分(0)) = 键 Then                读配置 = Trim(部分(1))                Exit Do            End If        End If    Loop    文件.CloseEnd FunctionSub 初始化配置()    Dim fso As Object, 路径 As String, 文件 As Object    路径 = ThisWorkbook.Path & "\config.txt"    Set fso = CreateObject("Scripting.FileSystemObject")    If Not fso.FileExists(路径) Then        Set 文件 = fso.CreateTextFile(路径, True)        文件.WriteLine "收件人=boss@company.com"        文件.WriteLine "导出路径="        文件.Close        MsgBox "已生成 config.txt,请修改收件人邮箱。", vbInformation    Else        MsgBox "config.txt 已存在。", vbInformation    End IfEnd Sub' ===== 邮件发送(番外篇5 Outlook) =====Sub 发送邮件(附件路径 As String)    Dim outlook As Object, 邮件 As Object    Dim 收件人 As String, 日期戳 As String    收件人 = 读配置("收件人")    If 收件人 = "" Then        MsgBox "未配置收件人,请在 config.txt 设置。", vbExclamation        Exit Sub    End If    日期戳 = Format(Date, "yyyy-mm-dd")    Set outlook = CreateObject("Outlook.Application")    Set 邮件 = outlook.CreateItem(0)    邮件.To = 收件人    邮件.Subject = "销售日报 " & 日期戳    邮件.Body = "领导好,附件是今日销售汇总,请查收。" & vbCrLf & "(本邮件由 Excel 宏自动生成)"    邮件.Attachments.Add 附件路径    邮件.Display   ' 先预览确认;想全自动直发改 邮件.SendEnd Sub' ===== 主过程:合并+汇总+导出+发邮件 =====Sub 跑日报并发送()    On Error GoTo 出错    合并待合并文件夹    按产品汇总销量    Dim 路径 As String    路径 = 导出销量汇总    发送邮件 路径    ThisWorkbook.Save    写运行记录 "日报已完成并发送,导出:" & 路径    MsgBox "日报已完成:" & vbCrLf & 路径, vbInformation    Exit Sub出错:    写运行记录 "出错:" & Err.Description    MsgBox "日报出错:" & Err.Description, vbCriticalEnd Sub

要点:config.txt 用 键=值 格式(收件人= / 导出路径=),读配置 按行 Split 解析;导出路径 留空时自动用工作簿目录。发邮件前从配置取收件人,没配就提示。邮箱安全沿用番外篇 5 的 .Display 预览确认。


案例 3(实用小案例):定时全自动——打开即排、关闭即撤、到点自己跑

功能说明:把案例 2 的"跑日报并发送"接进定时框架——打开工作簿自动安排每天 8:00 跑,关闭自动取消,到点自动执行并写运行记录。从此你只要每天把分店 Excel 丢进「待合并」,报表会自己合并、汇总、发邮件,你只管看运行记录。

操作步骤

  1. 案例 1、案例 2 的代码都已就位(含 跑日报并发送)。
  2. 在 ThisWorkbook 模块(双击工程里的 ThisWorkbook)粘贴第一段事件代码。
  3. 在标准模块顶部加 Public 日报运行时间 As Date,并粘贴第二段(安排/取消/定时跑)。
  4. 保存关闭后再打开——它已自动安排;关闭时自动取消,不再骚扰。
' —— 这段代码放在【ThisWorkbook】模块里 ——Private Sub Workbook_Open()    安排每日日报        ' 打开即自动安排End SubPrivate Sub Workbook_BeforeClose(Cancel As Boolean)    取消每日日报        ' 关闭前自动取消,防关掉后还被触发End Sub
' —— 这段代码放在【标准模块】里(顶部先加 Public 变量) ——Public 日报运行时间 As DateSub 安排每日日报()    日报运行时间 = Date + TimeValue("08:00:00")    Application.OnTime 日报运行时间, "定时跑日报"End SubSub 取消每日日报()    On Error Resume Next    Application.OnTime 日报运行时间, "定时跑日报", , False   ' 末尾 False = 取消End SubSub 定时跑日报()    跑日报并发送        ' 直接调案例2主流程(合并/汇总/导出/发邮件)    日报运行时间 = Date + 1 + TimeValue("08:00:00")    Application.OnTime 日报运行时间, "定时跑日报"   ' 安排明天,保持循环End Sub

要点:事件代码必须在 ThisWorkbook 模块。Workbook_Open 打开即排、Workbook_BeforeClose 关闭即撤,配合 定时跑日报 末尾再排明天,实现"开即排、关即撤、每天自动跑"。定时跑日报 直接调 跑日报并发送,把前面所有零件一次性串起来——这就是"全自动日报机"的最终形态。想把发送改成全自动直发,把 发送邮件 里的 邮件.Display 换成 邮件.Send 即可(需 Outlook 已登录且允许程序发信)。


本篇小结

  • 五个零件一条龙合并待合并文件夹(FSO+合并,番外篇3)→ 按产品汇总销量(字典,番外篇1/4)→ 导出销量汇总(SaveAs 51,番外篇5)→ 发送邮件(Outlook,番外篇5)→ 写运行记录(日志)。
  • 配置贯穿config.txt 用 键=值 记住收件人/导出路径(FSO 读写,番外篇2),换环境只改文件不动代码。
  • 定时驱动Application.OnTime + Workbook_Open 安排 + Workbook_BeforeClose 取消(番外篇6),实现每天 8:00 自动跑。
  • 三道保险On Error 兜底写日志不崩;邮件先 .Display 确认再 .Send;关闭前必取消定时防骚扰。
  • 完整工具已成:主系列 20 篇筑底 + 番外篇 1~6 进阶,本收尾篇把它们焊成一台"自动日报机",可每日无人值守产出并送达。

下一篇内容预告

本篇是《从0学Excel VBA编程》收尾篇——主系列 20 篇 + 番外篇 1~6 + 本收尾篇,已完整覆盖"从 0 到能手搓自动化工具"的全路径,系列到此圆满收官,无下一篇

如果你想继续深造,可选方向:

  • 进阶番外(可选):在 VBA 里用 SQL(直接 SELECT 筛选汇总,比循环更清爽);
  • 实战拓展:给日报机加"异常自动微信/邮件告警""多套模板切换""历史数据归档"等。 需要哪个,告诉我就行。