3.5.4-代码解析:S0201_文件处理

S0201_文件处理(longName, shortName),这里的longName, shortName称为参数,在本书之前介绍的Sub过程括号中无任何信息。

当一个需求比较复杂时,我们会将其分隔成几个Sub过程去完成,某一个过程对应的功能可能被重复调用,只是每次使用的参数不同,这样我们就需要带参数的Sub过程。如本示例中,需要将不同员工的数据读入数据缓存工作表。对于每个员工的操作基本是一样的,每名员工信息占据一列,依次写入。

基本逻辑过程如下:

1)打开员工的数据工作簿

2)获取当前数据缓存工作表最大列maxCol

3)将新员工信息写入maxCol+1列

代码如下

1       Sub S0201_文件处理(longName, shortName)
2           Set wb = Workbooks.Open(longName) '打开工作簿
3           Set sht = wb.Worksheets(1)
4           '获取员工姓名
5           employeeName = Split(shortName, "-")(0)
6           Debug.Print (employeeName)
7           '获取输入Excel最大行
8           maxRow = sht.Cells(Rows.Count, "B").End(xlUp).Row
9           
10          ' 拟输入列列号
11          Set shtData = ThisWorkbook.Worksheets("数据缓存")
12          a1Value = shtData.Range("A1")
13          If a1Value = "" Then
14              inputCol = 1
15          Else
16          		inputCol=shtData.Cells(1,Columns.Count).End(xlToLeft).Column + 1
17          End If
18          
19          shtData.Cells(1, inputCol) = employeeName
20          
21          ' 复制每个员工的数据至目标工作表
22          sht.Range("B2:B" & maxRow).Copy Destination:=shtData.Cells(2, inputCol)
23
24          wb.Close
25      End Sub

代码中文解析

1       Sub S0201_文件处理(longName, shortName)
2           打开文件地址为longName的Excel工作簿,用变量wb表示
3           定义工作表sht,表示wb工作簿的第1个工作表,该工作簿只含有1个工作表
4           '获取员工姓名
5           表示文件名的字符串,使用Split函数进行分割,获取员工姓名
6           输出显示员工姓名
7           '获取输入Excel最大行
8           sht工作表B列最大行
9           
10          ' 拟输入列列号
11          定义数据缓存工作表为shtData
12          获取shtData工作表A1单元格内容a1Value
13          判断开始:a1Value是否为空
14              如果是,则inputCol = 1
15          如果不是
16              inputCol为shtData工作表第1列最大行+1
17          循环结束
18          
19          shtData单元格(行号=1,列号=inputCol)赋值员工姓名employeeName
20          
21          ' 复制每个员工的数据至目标工作表
22          将员工工作表B2至B最大行区域复制,在单元格(行号=2,列号=inputCol)处粘贴
23
24          关闭工作簿wb
25      End Sub

其实就是将员工生产的小蛋糕重量信息分别复制到数据缓存工作表,因为不知道员工有多少信息(即多少行),以及不知道数据缓存工作表已有多少信息。所以需要找到每名员工有多少行信息,以及当前数据缓存表中当前写到哪一列。

关键代码解读

1)第2行Set wb = Workbooks.Open(longName)longName为对应Excel文件的绝对地址。记得使用完毕后,务必关闭该Excel文件,wb.Close。之前的示例中所有的操作都是在代码所在Excel工作簿,使用ThisWorkbook表征就可以,当拟操作的Excel不是当前代码所在Excel文件,需要先获取拟操作的Excel对象,也就是这里的wb。

2)第3行Set sht = wb.Worksheets(1),获取wb工作簿的第1个Excel工作表。在之前的示例中,我们通过工作表名称获取工作表信息,Worksheets(“工作表名”),同样可以通过位置获取。该方法请慎用,当Excel工作簿中包括多个工作表时,若人工移动Excel工作表,同样的位置信息表示的会是不同的工作表,所以建议在工作簿中只含有一个工作表时使用该方法。

3)第5行employeeName = Split(shortName, "-")(0),字符串分割函数,当文件名为“员工丙-小蛋糕重量.xlsx”时,以-为分隔符,生成一个数组,如图3-22所示,获取数组第一个元素(从0开始计数)为员工姓名,可以从图3-23有直观的感受。可以看到数据源的标准化是很重要的,如果员工反馈的Excel文件是任意命名的,那么就不能获取其姓名,标准化的数据源大大减少代码体量。


../_images/3-22.png

图3-22 Split函数

../_images/3-23.png

图3-23 Split分割的效果图


数组是什么?可以看做一个容器,可以将数据放入进去暂存,当程序运行结束后,自动消失,但对它的读写速度远远高于对于Excel文件的读写。这里先只介绍一维数组,类似于Excel中的一行,每个单元格可以分别写入信息,如图3-24所示。通过关键字Array定义一个新数组,数组有如下特征:

  • 从本地窗口中也可以看出数组是从0开始计数的

  • 数组中每个元素的数据类型可以不同

  • Ubound获取数组最大序列号

  • Lbound获取数组最小序列号

  • Debug.Print(a),在程序运行过,输出变a到立即窗口中。但不能直接输出数组,可以输出其每一个元素。数组元素获取,arr(i),i表示在数组的位置


../_images/3-24.png

图3-24 一维数组介绍


4)第22行sht.Range("B2:B" & maxRow).Copy Destination:=shtData.Cells(2, inputCol),复制工作表区域,Copy前为拟复制区域,Destination:=后为复制到的新位置第一个单元格。